队列和栈
一、队列
1.设计循环队列(非常有用)
MyCircularQueue(k): 构造器,设置队列长度为 k 。 Front: 从队首获取元素。如果队列为空,返回 -1 。 Rear: 获取队尾元素。如果队列为空,返回 -1 。 enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。 deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。 isEmpty(): 检查循环队列是否为空。 isFull(): 检查循环队列是否已满。
//数组链表都可以设计循环队列
public class Node{ int val; Node next; public Node(int x){ this.val=x; } } class MyCircularQueue{ int size; Node head; Node tail; int count; public MyCircularQueue(int k){ this.size=k; this.count=0; } public boolean isEmpty() { return count==0; } public boolean isFull(){ return count==size; } public int Front() { if(isEmpty()){ return -1; } return head.val; } public int Rear() { if(isEmpty()){ return -1; } return tail.val; } public boolean enQueue(int value) { if(isFull()){ return false; } if(head==null) { head=tail=new Node(value); } else{ Node node=new Node(value); tail.next=node; tail=tail.next; } this.count++; return true; } public boolean deQueue() { if(isEmpty()){ return false; } head=head.next; this.count--; return true; } }
如果有能力的可以自己再设计一个优先队列(例如老人比年轻人更优先,这时就需要再加一个整形变量来判断力)
2.数据流中的移动平均值
如果数据超过4个则每次求平均值保留最后进去的四个。
3.队列与广度优先遍历(BFS)
广度优先遍历的模板
/** * Return the length of the shortest path between root and target node. */ int BFS(Node root, Node target) { Queue<Node> queue; // store all nodes which are waiting to be processed int step = 0; // number of steps neeeded from root to current node // initialize add root to queue; // BFS while (queue is not empty) { step = step + 1; // iterate the nodes which are already in the queue int size = queue.size(); for (int i = 0; i < size; ++i) { Node cur = the first node in queue; return step if cur is target; for (Node next : the neighbors of cur) { add next to queue; } remove the first node from queue; } } return -1; // there is no path from root to target }
1)墙与门(通过这个判断目标离另一个目标的距离有多远(最短距离))
private static int[][] SETP_ARRAY = {{0,1},{0,-1},{1,0},{-1,0}}; public void wallsAndGates(int[][] rooms) { int row = rooms.length; if (row == 0){ return; } int column = rooms[0].length; Queue queue = new LinkedList(); // 1、先遍历一遍把所有的门节点找出,并入队 for (int i = 0; i < row; i++){ for (int j = 0; j < column; j ++){ int value = rooms[i][j]; if (value == 0){ queue.add(new Point(i,j)); } } } // 2、按照门节点做多源BFS,这样每次只要空房间出队就是到多个门的最短距离 while (!queue.isEmpty()){ Point point = (Point)queue.poll(); int x = point.x; int y = point.y; for (int[] step : SETP_ARRAY){ int pointX = step[0] + x; int pointY = step[1] + y; if (pointX < 0 || pointY < 0 || pointX >= row || pointY >= column || rooms[pointX][pointY] != Integer.MAX_VALUE){ continue; } rooms[pointX][pointY] = rooms[x][y] + 1; queue.add(new Point(pointX,pointY)); } } } class Point{ int x; int y; public Point(int x,int y){ this.x = x; this.y = y; } }
2)打开转盘锁
public int openLock(String[] deadends, String target) { if ("0000".equals(target)) { return 0; } Set<String> set = new HashSet<>(); Queue<String> queue = new LinkedList<>(); for (String temp:deadends ) { set.add(temp); } if(set.contains("0000")) { return -1; } int count=0; queue.offer("0000"); set.add("0000"); while(!queue.isEmpty()) { count++; int size=queue.size(); for (int i=0;i<size;i++) { String ch=queue.poll(); for (String string:getStr(ch) ) { if(!set.contains(string)) { if(string.equals(target)) { return count; } queue.offer(string); set.add(string); } } } } return -1; } public char sumadd(char temp) { return temp == '9' ? '0' : (char) (temp + 1); } public char sumsub(char temp) { return temp == '0' ? '9' : (char) (temp - 1); } public List<String> getStr(String temp) { char[] atr = temp.toCharArray(); List<String> ret = new ArrayList<>(); for (int i = 0; i < 4; i++) { char num = atr[i]; atr[i] = sumadd(num); ret.add(new String(atr)); atr[i] = sumsub(num); ret.add(new String(atr)); atr[i] = num; } return ret; }
比较1)和2),1)并没有queue.size()循环了再求每个结点的下一个,而2)把所有节点都遍历了。一个是求最短距离,一个是求变化了多少次,最短距离就需要每个节点都进行变化才可以求到指定节点的变化。
二、栈
1.设计最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。 pop() —— 删除栈顶的元素。 top() —— 获取栈顶元素。 getMin() —— 检索栈中的最小元素。
public class Node{ int val; Node next; int min; public Node(int x) { this.val=x; } } class MinStack{ Node cur; int count; public void push(int x) { if(cur==null) { cur=new Node(x); cur.min=x; } else{ Node node=new Node(x); node.min=Math.min(x,cur.min); node.next=cur; cur=node; } count++; } public void pop(){ if(count==0) { return; } cur=cur.next; } public int top(){ if(count==0) { return -1; } return cur.val; } public int getMin(){ if(count==0) { return -1; } return cur.min; } }
2.深度优先遍历
/* * Return true if there is a path from cur to target. */ boolean DFS(Node cur, Node target, Set<Node> visited) { return true if cur is target; for (next : each neighbor of cur) { if (next is not in visited) { add next to visted; return true if DFS(next, target, visited) == true; } } return false; }
克隆图:
public Node cloneGraph(Node node) { return clone(node,new HashMap()); } public Node clone(Node node,Map<Integer,Node> map) { if(node==null) { return null; } if(map.containsKey(node.val)) { return map.get(node.val); } Node node1=new Node(node.val,new ArrayList()); map.put(node1.val,node1); for(Node data:node.neighbors) { node1.neighbors.add(clone(data,map)); } return node1; }
dfs模板2
/* * Return true if there is a path from cur to target. */ boolean DFS(int root, int target) { Set<Node> visited; Stack<Node> s; add root to s; while (s is not empty) { Node cur = the top element in s; return true if cur is target; for (Node next : the neighbors of cur) { if (next is not in visited) { add next to s; add next to visited; } } remove cur from s; } return false; }