1. 程式人生 > >LeetCode刷題記錄(五)

LeetCode刷題記錄(五)

LeetCode刷題記錄(五)

今天開始佇列&棧卡片的學習。

1、設計迴圈佇列

題目:
在這裡插入圖片描述
在這裡插入圖片描述
我的思路:

迴圈佇列的工作原理可以參考LeetCode上的介紹,從介紹中我們可以看到:

  1. 可以定義一個數組來儲存佇列中的元素,迴圈佇列定義了兩個指標,一個指標指向的是佇列的起始位置,一個指標指向的是佇列的結尾;
  2. 當佇列為空時,起始指標和尾指標都是指向的佇列之外,向佇列中新增一個元素之後,起始指標和尾指標都指向佇列的第一位,以後每新增一個元素,尾指標都會向後移動一位;
  3. 當刪除一個元素時,起始指標都要向後移動一位,當刪除佇列最後一個元素之後,起始指標和尾指標都指向佇列之外;
  4. 如果移動起始指標和尾指標到了陣列的結尾,下一個位置可以重新指向陣列的起始位置,以形成一個環形的結構;
  5. 當佇列起始指標和尾指標都指向佇列之外的時候,可以認為佇列是空的;
  6. 如果佇列的尾指標指向位置的下一個位置也是起始指標指向的位置,可以認為佇列是滿的。

迴圈佇列實現的關鍵是判斷佇列是滿的和空的的策略。

按照這個思路實現的程式碼如下:

public class MyCircularQueue {
	//起始指標
	private int front;
	//尾指標
	private int rear;
	//定義陣列存放佇列的元素
	private int[] queue;
/** Initialize your data structure here. Set the size of the queue to be k. */ public MyCircularQueue(int k) { //初始化起始指標、尾指標和佇列 queue = new int[k]; front = -1; rear = -1; } /** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) { //如果佇列已滿,則無法插入元素,返回false if(isFull()) { return false; } if(isEmpty()) { //佇列是空的,起始指標和截止指標都要向後移動一位,在尾指標指向的位置插入值 front++; rear++; queue[rear] = value; return true; } else { //尾指標向後移動一位,如果已經移動到最後,則尾指標指向0,在尾指標指向的位置插入值 rear = rear + 1 >= queue.length ? 0 : rear + 1; queue[rear] = value; return true; } } /** Delete an element from the circular queue. Return true if the operation is successful. */ public boolean deQueue() { //如果佇列是空的,則無法取出元素,返回false if(isEmpty()) { return false; } if(front == rear) { //如果起始指標和尾指標指向同一個值,說明這個值是佇列的最後一個元素,移除這個元素後佇列就空了,需要將起始指標和尾指標都置為-1以便從頭開始 front = -1; rear = -1; return true; } else { //起始指標向後移動一位,如果起始指標已經移動到最後,則指向0 front = front + 1 >= queue.length ? 0 : front + 1; return true; } } /** Get the front item from the queue. */ public int Front() { //如果佇列為空,則返回-1,否則返回起始指標指向的值 if(isEmpty()) { return -1; } return queue[front]; } /** Get the last item from the queue. */ public int Rear() { //如果佇列為空,則返回-1,否則返回尾指標指向的值 if(isEmpty()) { return -1; } return queue[rear]; } /** Checks whether the circular queue is empty or not. */ public boolean isEmpty() { //如果起始指標指向-1,說明指標還沒開始移動,佇列為空 return front == -1; } /** Checks whether the circular queue is full or not. */ public boolean isFull() { //根據尾指標獲取佇列結尾下一個元素,如果下一個元素就是起始指標指向的元素,說明佇列已經滿了 int next = rear + 1 >= queue.length ? 0 : rear + 1; if(next == front) { return true; } else { return false; } } }

2、島嶼的個數

題目:
在這裡插入圖片描述

我的思路:

這一題思路是廣度優先搜尋(BFS),在佇列&棧卡片中有介紹 ,根據這裡的介紹我的想法是這樣的:

  1. 可以定義一個佇列用於臨時存放陣列中的元素,定義一個列表儲存使用過的元素;
  2. 依次遍歷二維陣列中每個元素,如果這個元素的值是’0’,或者這個元素已經被使用過了,則直接跳過;
  3. 如果元素值是’1’並且沒有被使用過,則將該元素加入到佇列和列表中,如果佇列不為空,遍歷佇列,獲取佇列中第一個元素的前後左右四個位置的元素,如果獲取到的元素值為’1’並且沒有使用過,就加入到佇列和列表中,然後將佇列的第一個元素刪除,每次迴圈都刪除上次迴圈獲取到的所有佇列元素,就這樣迴圈直到最後一個元素從佇列中刪除說明獲取到一個島嶼;
  4. 按照這個思路依次遍歷陣列中所有的元素,獲取到所有的島嶼個數。

按照這個思路實現的程式碼如下:

public class IslandNum {

	public static void main(String[] args) {
		char[][] grid = new char[4][5];
		grid[0] = new char[] {'1', '1', '0', '0', '0'};
		grid[1] = new char[] {'1', '1', '0', '0', '0'};
		grid[2] = new char[] {'0', '0', '1', '0', '0'};
		grid[3] = new char[] {'0', '0', '0', '1', '1'};

		System.out.println(new IslandNum().numIslands(grid));
	}

	public int numIslands(char[][] grid) {
		//佇列臨時存放元素
        Queue<Index> islands = new LinkedList<Index>();
        //列表儲存已經使用過的元素
        List<Index> usedIndex = new ArrayList<Index>();
        int num = 0;
        
        //二維陣列是空的情況
        if(grid == null || grid.length == 0 ||
        		grid[0] == null || grid[0].length == 0) {
        	return num;
        }
        
        //遍歷二維陣列
        for(int i = 0; i < grid.length; i++) {
        	for(int j = 0; j < grid[0].length; j++) {
        		//如果陣列元素是0或者已經使用過了,直接跳過
        		if(grid[i][j] == '0' || usedIndex.contains(new Index(i, j))) {
        			continue;
        		}
        		
        		//如果陣列元素是1且沒有使用過,則進行遍歷
        		if(grid[i][j] == '1' && !usedIndex.contains(new Index(i, j))) {
        			//向佇列和列表中新增該元素
        			islands.add(new Index(i, j));
        			usedIndex.add(new Index(i, j));
        			
        			while(!islands.isEmpty()) {
        				int size = islands.size();
        				//遍歷佇列,獲取佇列中第一個元素前後左右的元素,如果是1並且沒有使用過,加入到佇列和列表中
        				//因為這裡迴圈每次都會刪除第一個元素,所以每一輪迴圈次數都是迴圈上一輪迴圈新新增進佇列元素的個數
        				//這個思路就類似於BFS
        				for(int k = 0; k < size; k++) {
        					Index head = islands.peek();
	        				if(head.row + 1 < grid.length) {
	        					if(grid[head.row + 1][head.col] == '1' 
	        							&& !usedIndex.contains(new Index(head.row + 1, head.col))) {
	        						islands.add(new Index(head.row + 1, head.col));
	        						usedIndex.add(new Index(head.row + 1, head.col));
	        					}
	        				}
	        				if(head.col + 1 < grid[0].length) {
	        					if(grid[head.row][head.col + 1] == '1'
	        							&& !usedIndex.contains(new Index(head.row, head.col + 1))) {
	        						islands.add(new Index(head.row, head.col + 1));
	        						usedIndex.add(new Index(head.row, head.col + 1));
	        					}
	        				}
        					if(head.row - 1 >= 0) {
        						if(grid[head.row - 1][head.col] == '1'
        								&& !usedIndex.contains(new Index(head.row - 1, head.col))) {
        							islands.add(new Index(head.row - 1, head.col));
	        						usedIndex.add(new Index(head.row - 1, head.col));
        						}
        					}
        					if(head.col - 1 >= 0) {
	        					if(grid[head.row][head.col - 1] == '1'
	        							&& !usedIndex.contains(new Index(head.row, head.col - 1))) {
	        						islands.add(new Index(head.row, head.col - 1));
	        						usedIndex.add(new Index(head.row, head.col - 1));
	        					}
	        				}

        					//刪除佇列的第一個元素
	        				islands.poll();
        				}
        			}
        			//當佇列全部清空後,島嶼數量加1
        			num++;
        		}
        	}
        }
        
        return num;
    }
	
}

/**
 * 定義一個內部類儲存二維陣列的索引
 *
 */
class Index {
	int row;
	int col;
	
	public Index(int row, int col) {
		this.row = row;
		this.col = col;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof Index)) {
			return false;
		}
		
		Index i = (Index) obj;
		if(this.row == i.row && this.col == i.col) {
			return true;
		}
		return false;
	}
	
	@Override
	public String toString() {
		return " (" + row + "," + col + ") ";
	}
}

反思:

按照上面這個思路雖然能夠解決問題,但是時間複雜度比較高,我在LeetCode上提交之後也是最後一個有十多萬資料的大陣列會報超時的問題,暫時沒有得到解決,上網搜了一下有通過遞迴的思路解題的,我暫時還沒有研究,後續解決了再更新這題的解法。