今天开始队列&栈卡片的学习。
循环队列的工作原理可以参考LeetCode上的介绍,从介绍中我们可以看到:
循环队列实现的关键是判断队列是满的和空的的策略。
按照这个思路实现的代码如下:
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;
}
}
}
我的思路:
这一题思路是广度优先搜索(BFS),在队列&栈卡片中有介绍 ,根据这里的介绍我的想法是这样的:
按照这个思路实现的代码如下:
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上提交之后也是最后一个有十多万数据的大数组会报超时的问题,暂时没有得到解决,上网搜了一下有通过递归的思路解题的,我暂时还没有研究,后续解决了再更新这题的解法。