LeetCode刷题记录(五)

LeetCode刷题记录(五)

今天开始队列&栈卡片的学习。

1、设计循环队列

题目:
LeetCode刷题记录(五)_第1张图片
LeetCode刷题记录(五)_第2张图片
我的思路:

循环队列的工作原理可以参考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、岛屿的个数

题目:
LeetCode刷题记录(五)_第3张图片

我的思路:

这一题思路是广度优先搜索(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上提交之后也是最后一个有十多万数据的大数组会报超时的问题,暂时没有得到解决,上网搜了一下有通过递归的思路解题的,我暂时还没有研究,后续解决了再更新这题的解法。

你可能感兴趣的:(数据结构与算法,LeetCode)