链表
206. 反转链表
-
题目描述
-
题解
class Solution { public ListNode reverseList(ListNode head) { ListNode pre=null; ListNode cur=head; while(cur!=null){ ListNode temp=cur.next; cur.next=pre; pre=cur; cur=temp; } return pre; } }
25. K 个一组翻转链表
-
题目描述
-
题解
class Solution { public ListNode reverseKGroup(ListNode head, int k) { if(head==null || head.next==null) return head; ListNode tail=head; for(int i=0;i<k;i++){ if(tail==null) return head; tail=tail.next; } ListNode pre=reverse(head,tail); head.next=reverseKGroup(tail,k); return pre; } public ListNode reverse(ListNode head,ListNode tail){ ListNode pre=null; ListNode cur=head; while(cur!=tail){ ListNode temp=cur.next; cur.next=pre; pre=cur; cur=temp; } return pre; } }
141. 环形链表
-
题目描述
-
题解
public class Solution { public boolean hasCycle(ListNode head) { ListNode fast=head; ListNode slow=head; while(fast!=null && fast.next!=null){ fast=fast.next.next; slow=slow.next; if(slow==fast){ return true; } } return false; } }
21. 合并两个有序链表
-
题目描述
-
题解
class Solution { public ListNode mergeTwoLists(ListNode list1, ListNode list2) { if(list1==null) return list2; if(list2==null) return list1; if(list1.val>list2.val){ list2.next=mergeTwoLists(list1,list2.next); return list2; }else{ list1.next=mergeTwoLists(list1.next,list2); return list1; } } }
142. 环形链表 II
-
题目描述
-
题解
public class Solution { public ListNode detectCycle(ListNode head) { if(head==null) return head; ListNode fast=head; ListNode slow=head; while(fast!=null && fast.next!=null){ fast=fast.next.next; slow=slow.next; if(fast==slow){ fast=head; while(fast!=slow){ fast=fast.next; slow=slow.next; } return slow; } } return null; } }
138. 复制带随机指针的链表
-
题目描述
-
题解
class Solution { public Node copyRandomList(Node head) { if(head == null) return head; // map方法,空间复杂度O(n) Node node = head; // 使用hash表存储旧结点和新结点的映射 Map<Node,Node> map = new HashMap<>(); while(node != null){ Node clone = new Node(node.val,null,null); map.put(node,clone); node = node.next; } node = head; while(node != null){ map.get(node).next = map.get(node.next); map.get(node).random = map.get(node.random); node = node.next; } return map.get(head); } }
148. 排序链表
-
题目描述
-
题解
class Solution { /** * 归并排序法:在动手之前一直觉得空间复杂度为常量不太可能,因为原来使用归并时,都是 O(N)的, * 需要复制出相等的空间来进行赋值归并。对于链表,实际上是可以实现常数空间占用的(链表的归并 * 排序不需要额外的空间)。利用归并的思想,递归地将当前链表分为两段,然后merge,分两段的方 * 法是使用 fast-slow 法,用两个指针,一个每次走两步,一个走一步,知道快的走到了末尾,然后 * 慢的所在位置就是中间位置,这样就分成了两段。merge时,把两段头部节点值比较,用一个 p 指向 * 较小的,且记录第一个节点,然后 两段的头一步一步向后走,p也一直向后走,总是指向较小节点, * 直至其中一个头为NULL,处理剩下的元素。最后返回记录的头即可。 * * 主要考察3个知识点, * 知识点1:归并排序的整体思想 * 知识点2:找到一个链表的中间节点的方法 * 知识点3:合并两个已排好序的链表为一个新的有序链表 */ public ListNode sortList(ListNode head) { return head == null ? null : mergeSort(head); } private ListNode mergeSort(ListNode head) { if (head.next == null) { return head; } ListNode p = head, q = head, pre = null; while (q != null && q.next != null) { pre = p; p = p.next; q = q.next.next; } pre.next = null; ListNode l = mergeSort(head); ListNode r = mergeSort(p); return merge(l, r); } ListNode merge(ListNode l, ListNode r) { ListNode dummyHead = new ListNode(0); ListNode cur = dummyHead; while (l != null && r != null) { if (l.val <= r.val) { cur.next = l; cur = cur.next; l = l.next; } else { cur.next = r; cur = cur.next; r = r.next; } } if (l != null) { cur.next = l; } if (r != null) { cur.next = r; } return dummyHead.next; } }
23. 合并K个升序链表
-
题目描述
-
题解
class Solution { public ListNode mergeKLists(ListNode[] lists) { if(lists.length==0) return null; else if(lists.length==1) return lists[0]; else if(lists.length==2) return mergeTwoList(lists[0],lists[1]); else{ int mid=lists.length/2; ListNode[] l1=new ListNode[mid]; for(int i=0;i<mid;i++){ l1[i]=lists[i]; } ListNode[] l2=new ListNode[lists.length-mid]; for(int i=mid,j=0;i<lists.length;i++,j++){ l2[j]=lists[i]; } return mergeTwoList(mergeKLists(l1),mergeKLists(l2)); } } public ListNode mergeTwoList(ListNode l1,ListNode l2){ if(l1==null) return l2; if(l2==null) return l1; if(l1.val>l2.val){ l2.next=mergeTwoList(l1,l2.next); return l2; }else{ l1.next=mergeTwoList(l1.next,l2); return l1; } } }
92. 反转链表 II
-
题目描述
-
题解
class Solution { public ListNode reverseBetween(ListNode head, int left, int right) { if(head==null) return head; ListNode dummy=new ListNode(-1); dummy.next=head; ListNode pre=dummy; //找到反转的入口节点的前驱节点 for(int i=0;i<left-1;i++){ pre=pre.next; } ListNode cur=pre.next; for(int i=0;i<right-left;i++){ ListNode temp=cur.next; cur.next=temp.next; temp.next=pre.next; pre.next=temp; } return dummy.next; } }
24. 两两交换链表中的节点
-
题目描述
-
题解
class Solution { public ListNode swapPairs(ListNode head) { if(head==null) return head; ListNode dummy=new ListNode(-1); dummy.next=head; ListNode cur=head; ListNode pre=dummy; while(cur!=null && cur.next!=null){ ListNode temp=cur.next.next; pre.next=cur.next; cur.next.next=cur; cur.next=temp; pre=cur; cur=cur.next; } return dummy.next; } }
160. 相交链表
-
题目描述
-
题解
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode l1 = headA; ListNode l2 = headB; int len1 = 0, len2 = 0; while (l1 != null) { len1++; l1 = l1.next; } while (l2 != null) { len2++; l2 = l2.next; } l1 = headA; l2 = headB; if (len2 > len1) { int temp=len2; len2 = len1; len1 = temp; ListNode tempNode = l2; l2 = l1; l1 = tempNode; } int gap = len1 - len2; while (gap-- > 0) { l1 = l1.next; } while (l1 != l2) { l1 = l1.next; l2 = l2.next; } return l1; } }
143. 重排链表
-
题目描述
-
题解
class Solution { public void reorderList(ListNode head) { if(head==null) return; ListNode l1 = head; //找链表中点 ListNode mid = middleNode(head); ListNode l2 = mid.next; //断开中点 mid.next = null; //反转右半段 l2 = reverse(l2); //合并两个链表 merge(l1, l2); } public ListNode middleNode(ListNode head) { ListNode fast = head; ListNode slow = head; while (fast != null && fast.next != null) { fast=fast.next.next; slow = slow.next; } return slow; } public ListNode reverse(ListNode head) { ListNode pre = null; ListNode cur = head; while (cur != null) { ListNode temp=cur.next; cur.next=pre; pre=cur; cur = temp; } return pre; } public void merge(ListNode l1, ListNode l2) { while (l1 != null && l2 != null) { ListNode temp1 = l1.next; ListNode temp2 = l2.next; l1.next=l2; l1 = temp1; l2.next=l1; l2 = temp2; } } }
109. 有序链表转换二叉搜索树
-
题目描述
-
题解
class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null) return null; else if(head.next == null) return new TreeNode(head.val); ListNode pre = head; ListNode p = pre.next; ListNode q = p.next; //找到链表的中点p while(q!=null && q.next!=null){ pre = pre.next; p = pre.next; q = q.next.next; } //将中点左边的链表分开 pre.next = null; TreeNode root = new TreeNode(p.val); root.left = sortedListToBST(head); root.right = sortedListToBST(p.next); return root; } }
面试题 02.05. 链表求和
-
题目描述
-
题解
class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { int carry=0; ListNode dummy=new ListNode(-1); ListNode cur=dummy; while(l1!=null || l2!=null || carry!=0){ int num1=l1==null?0:l1.val; int num2=l2==null?0:l2.val; int sum=num1+num2+carry; ListNode temp=new ListNode(sum%10); cur.next=temp; cur=cur.next; carry=sum/10; l1=l1==null?null:l1.next; l2=l2==null?null:l2.next; } return dummy.next; } }
剑指 Offer 52. 两个链表的第一个公共节点
-
题目描述
-
题解
class Solution { ListNode getIntersectionNode(ListNode headA, ListNode headB) { if(headA == null || headB == null) return null; ListNode n1 = headA; ListNode n2 = headB; while(n1 != n2){ n1 = n1 == null ? headB : n1.next; n2 = n2 == null ? headA : n2.next; } return n1; } }
146. LRU 缓存
-
题目描述
-
题解
/** 哈希表+双向链表 */ class LRUCache { class DLinkedNode{ int key; int value; DLinkedNode prev; DLinkedNode next; public DLinkedNode(){} public DLinkedNode(int key,int value){ this.key=key; this.value=value; } } private Map<Integer,DLinkedNode> map=new HashMap<>(); private int size; private int capacity; private DLinkedNode head,tail; public LRUCache(int capacity) { int size=0; this.capacity=capacity; head=new DLinkedNode(); tail=new DLinkedNode(); head.next=tail; tail.next=head; } public int get(int key) { DLinkedNode node=map.get(key); if(node==null) return -1; moveToHead(node); return node.value; } public void put(int key, int value) { DLinkedNode node=map.get(key); if(node==null){ DLinkedNode newNode=new DLinkedNode(key,value); map.put(key,newNode); addToHead(newNode); size++; if(size>capacity){ DLinkedNode tail=removeTail(); map.remove(tail.key); size--; } }else{ node.value=value; moveToHead(node); } } public void addToHead(DLinkedNode node){ node.prev=head; node.next=head.next; head.next.prev=node; head.next=node; } public void removeNode(DLinkedNode node){ node.prev.next = node.next; node.next.prev = node.prev; } private void moveToHead(DLinkedNode node) { removeNode(node); addToHead(node); } private DLinkedNode removeTail() { DLinkedNode res = tail.prev; removeNode(res); return res; } } /** * Your LRUCache object will be instantiated and called as such: * LRUCache obj = new LRUCache(capacity); * int param_1 = obj.get(key); * obj.put(key,value); */
栈
103. 二叉树的锯齿形层序遍历
-
题目描述
-
题解
class Solution { public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> res=new ArrayList<>(); if(root==null) return res; Deque<TreeNode> queue=new LinkedList<>(); queue.offer(root); int flag=0; while(!queue.isEmpty()){ int size=queue.size(); List<Integer> temp=new ArrayList<>(); if(flag%2==0){ for(int i=0;i<size;i++){ TreeNode node=queue.poll(); temp.add(node.val); if(node.left!=null) queue.offer(node.left); if(node.right!=null) queue.offer(node.right); } }else{ for(int i=0;i<size;i++){ TreeNode node=queue.pollLast(); temp.add(node.val); if(node.right!=null) queue.offerFirst(node.right); if(node.left!=null) queue.offerFirst(node.left); } } res.add(new ArrayList(temp)); flag++; } return res; } }
94. 二叉树的中序遍历
-
题目描述
-
题解
class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res=new ArrayList<>(); if(root==null) return res; Deque<TreeNode> stack=new LinkedList<>(); stack.push(root); while(!stack.isEmpty()){ TreeNode temp=stack.peek(); if(temp!=null){ stack.pop(); if(temp.right!=null) stack.push(temp.right); stack.push(temp); stack.push(null); if(temp.left!=null) stack.push(temp.left); }else{ stack.pop(); temp=stack.peek(); res.add(temp.val); stack.pop(); } } return res; } }
173. 二叉搜索树迭代器
-
题目描述
-
题解
class BSTIterator { private TreeNode cur; private Deque<TreeNode> stack; // 依次存放待遍历的节点 // 中序遍历: 左 》 根 》 右 public BSTIterator(TreeNode root) { cur = root; stack = new LinkedList<TreeNode>(); } public int next() { while (cur!=null){ //当前节点不为空 不停遍历左子树 直到 cur = null跳出 //此时栈顶元素是不为空的cur 左子树已经遍历了 “左”为null //只需要从栈顶弹出当前节点 去遍历“根” stack.push(cur); cur = cur.left; } // 如果cur为空 那么从栈顶弹出自己的父节点 返回对应的值 // 栈顶元素弹出 表示已经遍历过 // “根”遍历完 遍历“右” 循环往复 右子树又是先左后根 再右 cur = stack.pop(); int val = cur.val; cur = cur.right; return val; } public boolean hasNext() { // 栈为空 不代表遍历完毕 比如整棵树的左子树遍历完毕 根也遍历完毕 // 此时cur = root(根节点).right栈为空 // 如果cur不为空 说明右子树还未遍历 hasNext为true. return cur!=null || !stack.isEmpty(); } }
20. 有效的括号
-
题目描述
-
题解
class Solution { public boolean isValid(String s) { Stack<Character> stack=new Stack<>(); char[] sArr=s.toCharArray(); for(char c:sArr){ if(c=='('){ stack.push(')'); }else if(c=='{'){ stack.push('}'); }else if(c=='['){ stack.push(']'); }else{ if(stack.isEmpty() || stack.pop()!=c) return false; } } return stack.isEmpty(); } }
224. 基本计算器
-
题目描述
-
题解
class Solution { public int calculate(String s) { Stack<Integer> stack = new Stack<Integer>(); // sign 代表正负 int sign = 1, res = 0; int length = s.length(); for (int i = 0; i < length; i++) { char ch = s.charAt(i); if (Character.isDigit(ch)) { int cur = ch - '0'; while (i + 1 < length && Character.isDigit(s.charAt(i + 1))) cur = cur * 10 + s.charAt(++i) - '0'; res = res + sign * cur; } else if (ch == '+') { sign = 1; } else if (ch == '-') { sign = -1; } else if (ch == '(') { stack.push(res); res = 0; stack.push(sign); sign = 1; } else if (ch == ')') { res = stack.pop() * res + stack.pop(); } } return res; } }
227. 基本计算器 II
-
题目描述
-
题解
class Solution { public int calculate(String s) { int presign='+'; int num=0; Deque<Integer> stack=new LinkedList<>(); for(int i=0;i<s.length();i++){ if(Character.isDigit(s.charAt(i))){ //保存当前数字,如:12是两个字符,需要进位累加 //记录当前数字。先减,防溢出 num=num*10-'0'+s.charAt(i); } if(s.charAt(i) != ' ' && !Character.isDigit(s.charAt(i)) || i==s.length()-1){ switch(presign){ case '+': stack.push(num); break; case '-': stack.push(-num); break; case '*': stack.push(stack.pop()*num); break; default: stack.push(stack.pop()/num); } presign=s.charAt(i); num=0; } } int res=0; while(!stack.isEmpty()){ res+=stack.pop(); } return res; } }
155. 最小栈
-
题目描述
-
题解
class MinStack { Stack<Integer> stack; Stack<Integer> minStack; public MinStack() { stack=new Stack<>(); minStack=new Stack<>(); minStack.push(Integer.MAX_VALUE); } public void push(int val) { stack.push(val); minStack.push(Math.min(minStack.peek(),val)); } public void pop() { stack.pop(); minStack.pop(); } public int top() { return stack.peek(); } public int getMin() { return minStack.peek(); } }
394. 字符串解码
-
题目描述
-
题解
/** * 双栈解法: * 准备两个栈,一个存放数字,一个存放字符串 * 遍历字符串分4中情况 * 一、如果是数字 将字符转成整型数字 注意数字不一定是个位 有可能是十位,百位等 所以digit = digit*10 + ch - '0'; * 二、如果是字符 直接将字符放在临时字符串中 * 三、如果是"[" 将临时数字和临时字符串入栈 * 四、如果是"]" 将数字和字符串出栈 此时临时字符串res = 出栈字符串 + 出栈数字*res */ class Solution { public String decodeString(String s) { Deque<Integer> digitStack=new LinkedList<>(); Deque<StringBuilder> stringStack=new LinkedList<>(); int digit=0; StringBuilder res=new StringBuilder(); char[] sArr=s.toCharArray(); for(int i=0;i<sArr.length;i++){ if(sArr[i]=='['){ //如果是"[" 将临时数字和临时字符串入栈 digitStack.push(digit); stringStack.push(res); digit=0; res=new StringBuilder(); }else if(sArr[i]==']'){ //如果是"]" 将数字和字符串出栈 此时临时字符串res = 出栈字符串 + 出栈数字*res StringBuilder temp=stringStack.poll(); int count=digitStack.poll(); for(int j=0;j<count;j++){ temp.append(res.toString()); } res=temp; }else if(Character.isDigit(sArr[i])){ //如果是数字 将字符转成整型数字 ch-'0' //注意数字不一定是个位 比如100[a] 所以digit要*10 digit=digit*10-'0'+sArr[i]; }else{ //如果是字符 直接将字符放在临时字符串中 res.append(sArr[i]); } } return res.toString(); } }
402. 移掉 K 位数字
-
题目描述
-
题解
class Solution { public String removeKdigits(String num, int k) { Deque<Character> deque=new LinkedList<>(); char[] sArr=num.toCharArray(); for(int i=0;i<sArr.length;i++){ //当且仅当K>0 并且队尾元素大于要入队的元素的时候就把队尾元素移除掉 while(!deque.isEmpty() && k>0 && deque.peekLast()>sArr[i]){ deque.pollLast(); k--; } deque.offer(sArr[i]); } //此时如果K还大于0 队列里面的元素已经为单调不降了。则最后依次移除队列尾部剩余的k数次即可, //拿123456728 k=7 举例说明 //入队完后 队列里面为1228 此时k=2 所以还需要依次移除尾部2和8 剩余12即为最小 for(int i=0;i<k;i++){ deque.pollLast(); } StringBuilder res=new StringBuilder(); boolean falg=true; //从队列头部取出所有元素 while(!deque.isEmpty()){ char ch=deque.poll(); //防止前导0 也就是队头第一个元素==0 则需要跳过 if(falg && ch=='0'){ continue; } falg=false; res.append(ch); } return res.length()==0?"0":res.toString(); } }
42. 接雨水
-
题目描述
-
题解
class Solution { public int trap(int[] height) { Deque<Integer> stack=new LinkedList<>(); int area=0; for(int i=0;i<height.length;i++){ while(!stack.isEmpty() && height[stack.peek()]<height[i]){ int preIndex=stack.pop(); if(!stack.isEmpty()){ int h=Math.min(height[i],height[stack.peek()])-height[preIndex]; int w=i-stack.peek()-1; area+=w*h; } } stack.push(i); } return area; } }
84. 柱状图中最大的矩形
-
题目描述
-
题解
class Solution { public int largestRectangleArea(int[] heights) { Deque<Integer> stack=new LinkedList<>(); int area=0; stack.push(-1); for(int i=0;i<heights.length;i++){ while(stack.peek()!=-1 && heights[i]<heights[stack.peek()]){ area=Math.max(area,heights[stack.pop()]*(i-stack.peek()-1)); } stack.push(i); } while(stack.peek()!=-1){ area=Math.max(area,heights[stack.pop()]*(heights.length-stack.peek()-1)); } return area; } }
232. 用栈实现队列
-
题目描述
-
题解
class MyQueue { Stack<Integer> stackIn; Stack<Integer> stackOut; public MyQueue() { stackIn=new Stack<>(); stackOut=new Stack<>(); } public void push(int x) { stackIn.push(x); } public int pop() { dumpIn(); return stackOut.pop(); } public int peek() { dumpIn(); return stackOut.peek(); } public boolean empty() { return stackIn.isEmpty() && stackOut.isEmpty(); } public void dumpIn(){ if(!stackOut.isEmpty()) return; while(!stackIn.isEmpty()){ stackOut.push(stackIn.pop()); } } } /** * Your MyQueue object will be instantiated and called as such: * MyQueue obj = new MyQueue(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.peek(); * boolean param_4 = obj.empty(); */
946. 验证栈序列
-
题目描述
-
题解
class Solution { public boolean validateStackSequences(int[] pushed, int[] popped) { Deque<Integer> stack=new LinkedList<>(); int j=0; for(int i=0;i<pushed.length;i++){ stack.push(pushed[i]); while(!stack.isEmpty() && stack.peek()==popped[j]){ j++; stack.pop(); } } return stack.isEmpty(); } }
739. 每日温度
-
题目描述
-
题解
class Solution { public int[] dailyTemperatures(int[] temperatures) { int[] res=new int[temperatures.length]; Deque<Integer> stack=new LinkedList<>(); for(int i=0;i<temperatures.length;i++){ while(!stack.isEmpty() && temperatures[i]>temperatures[stack.peek()]){ int preIndex=stack.pop(); res[preIndex]=i-preIndex; } stack.push(i); } return res; } }
树
124. 二叉树中的最大路径和
-
题目描述
-
题解
class Solution { int res = Integer.MIN_VALUE; public int maxPathSum(TreeNode root) { /** 对于任意一个节点, 如果最大和路径包含该节点, 那么只可能是两种情况: 1. 其左右子树中所构成的和路径值较大的那个加上该节点的值后向父节点回溯构成最大路径 2. 左右子树都在最大路径中, 加上该节点的值构成了最终的最大路径 **/ getMax(root); return res; } private int getMax(TreeNode r) { if(r == null) return 0; //如果子树路径和为负则应当置0表示最大路径不包含子树 int left = Math.max(0, getMax(r.left)); int right = Math.max(0, getMax(r.right)); //判断在该节点包含左右子树的路径和是否大于当前最大路径和 res = Math.max(res, r.val + left + right); return Math.max(left, right) + r.val; } }
236. 二叉树的最近公共祖先
-
题目描述
-
题解
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { Deque<TreeNode> stack=new LinkedList<>(); if(root==null) return root; stack.push(root); while(!stack.isEmpty()){ TreeNode temp=stack.peek(); if(temp!=null){ if(temp.right!=null) stack.push(temp.right); if(temp.left!=null) stack.push(temp.left); stack.push(temp); stack.push(null); }else{ stack.pop(); temp=stack.peek(); if(temp==p)return p; else if(temp==q) return q; } } return null; } }
450. 删除二叉搜索树中的节点
-
题目描述
-
题解
class Solution { public TreeNode deleteNode(TreeNode root, int key) { if(root==null) return null; if(root.val>key){ root.left=deleteNode(root.left,key); }else if(root.val<key){ root.right=deleteNode(root.right,key); }else{ if(root.left==null) return root.right; if(root.right==null) return root.left; TreeNode tmp=root.right; while(tmp.left!=null){ tmp=tmp.left; } tmp.left=root.left; root=root.right; } return root; } }
297. 二叉树的序列化与反序列化
-
题目描述
-
题解
public class Codec { public String serialize(TreeNode root) { //用StringBuilder StringBuilder res = ser_help(root, new StringBuilder()); return res.toString(); } public StringBuilder ser_help(TreeNode root, StringBuilder str){ if(null == root){ str.append("null,"); return str; } str.append(root.val); str.append(","); str = ser_help(root.left, str); str = ser_help(root.right, str); return str; } public TreeNode deserialize(String data) { String[] str_word = data.split(","); List<String> list_word = new LinkedList<String>(Arrays.asList(str_word)); return deser_help(list_word); } public TreeNode deser_help(List<String> li){ if(li.get(0).equals("null")){ li.remove(0); return null; } TreeNode res = new TreeNode(Integer.valueOf(li.get(0))); li.remove(0); res.left = deser_help(li); res.right = deser_help(li); return res; } }
103. 二叉树的锯齿形层序遍历
-
题目描述
-
题解
class Solution { public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> res=new ArrayList<>(); if(root==null) return res; Deque<TreeNode> queue=new LinkedList<>(); queue.offer(root); int flag=0; while(!queue.isEmpty()){ int size=queue.size(); List<Integer> temp=new ArrayList<>(); if(flag%2==0){ for(int i=0;i<size;i++){ TreeNode node=queue.poll(); temp.add(node.val); if(node.left!=null) queue.offer(node.left); if(node.right!=null) queue.offer(node.right); } }else{ for(int i=0;i<size;i++){ TreeNode node=queue.pollLast(); temp.add(node.val); if(node.right!=null) queue.offerFirst(node.right); if(node.left!=null) queue.offerFirst(node.left); } } res.add(new ArrayList(temp)); flag++; } return res; } }
98. 验证二叉搜索树
-
题目描述
-
题解
class Solution { public boolean isValidBST(TreeNode root) { if(root==null) return true; Stack<TreeNode> stack = new Stack<>(); stack.push(root); Integer preNum = null; while (!stack.isEmpty()) { TreeNode node=stack.peek(); if(node!=null){ stack.pop(); if(node.right!=null) stack.push(node.right); stack.push(node); stack.push(null); if(node.left!=null) stack.push(node.left); }else{ stack.pop(); node = stack.peek(); if(preNum!=null && node.val<=preNum) return false; preNum=node.val; stack.pop(); } } return true; } }
94. 二叉树的中序遍历
-
题目描述
-
题解
class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res=new ArrayList<>(); if(root==null) return res; Deque<TreeNode> stack=new LinkedList<>(); stack.push(root); while(!stack.isEmpty()){ TreeNode temp=stack.peek(); if(temp!=null){ stack.pop(); if(temp.right!=null) stack.push(temp.right); stack.push(temp); stack.push(null); if(temp.left!=null) stack.push(temp.left); }else{ stack.pop(); temp=stack.peek(); res.add(temp.val); stack.pop(); } } return res; } }
543. 二叉树的直径
-
题目描述
-
题解
class Solution { int max=0; public int diameterOfBinaryTree(TreeNode root) { depth(root); return max; } public int depth(TreeNode node){ if(node==null) return 0; int left=depth(node.left); int right=depth(node.right); max=Math.max(max,left+right); return Math.max(left,right)+1; } }
110. 平衡二叉树
-
题目描述
-
题解
class Solution { public boolean isBalanced(TreeNode root) { return getHeight(root)==-1?false:true; } public int getHeight(TreeNode node){ if(node==null) return 0; int left=getHeight(node.left); if(left==-1) return -1; int right=getHeight(node.right); if(right==-1) return -1; if(Math.abs(left-right)>1){ return -1; }else{ return Math.max(left,right)+1; } } }
173. 二叉搜索树迭代器
-
题目描述
-
题解
class BSTIterator { private TreeNode cur; private Deque<TreeNode> stack; // 依次存放待遍历的节点 // 中序遍历: 左 》 根 》 右 public BSTIterator(TreeNode root) { cur = root; stack = new LinkedList<TreeNode>(); } public int next() { while (cur!=null){ //当前节点不为空 不停遍历左子树 直到 cur = null跳出 //此时栈顶元素是不为空的cur 左子树已经遍历了 “左”为null //只需要从栈顶弹出当前节点 去遍历“根” stack.push(cur); cur = cur.left; } // 如果cur为空 那么从栈顶弹出自己的父节点 返回对应的值 // 栈顶元素弹出 表示已经遍历过 // “根”遍历完 遍历“右” 循环往复 右子树又是先左后根 再右 cur = stack.pop(); int val = cur.val; cur = cur.right; return val; } public boolean hasNext() { // 栈为空 不代表遍历完毕 比如整棵树的左子树遍历完毕 根也遍历完毕 // 此时cur = root(根节点).right栈为空 // 如果cur不为空 说明右子树还未遍历 hasNext为true. return cur!=null || !stack.isEmpty(); } }
105. 从前序与中序遍历序列构造二叉树
-
题目描述
-
题解
class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { return traversal(preorder,0,preorder.length,inorder,0,inorder.length); } public TreeNode traversal(int[] preorder,int preStart,int preEnd,int[] inorder,int inStart,int inEnd){ if(inEnd-inStart<1) return null; if(inEnd-inStart==1) return new TreeNode(inorder[inStart]); //前序第一个节点就是root节点 int rootVal=preorder[preStart]; TreeNode res=new TreeNode(rootVal); //根据rootval 找到再中序中的位置 int rootIndex=0; for(int i=inStart;i<inEnd;i++){ if(inorder[i]==rootVal){ rootIndex=i; break; } } res.left=traversal(preorder,preStart+1,preStart+1+rootIndex-inStart,inorder,inStart,rootIndex);; res.right=traversal(preorder,preStart+rootIndex-inStart+1,preEnd,inorder,rootIndex+1,inEnd); return res; } }
96. 不同的二叉搜索树
-
题目描述
-
题解
class Solution { public int numTrees(int n) { int[] dp=new int[n+1]; dp[0]=1; dp[1]=1; for(int i=2;i<=n;i++){ for(int j=1;j<=i;j++){ dp[i]+=dp[j-1]*dp[i-j]; } } return dp[n]; } }
449. 序列化和反序列化二叉搜索树
-
题目描述
-
题解
public class Codec { // 队列+前序遍历 // Encodes a tree to a single string. public String serialize(TreeNode root) { if(root==null){return "";} StringBuilder ans=new StringBuilder(); preOrder(root,ans); return ans.toString(); } public void preOrder(TreeNode t,StringBuilder sb){ if(t==null){return;} sb.append("#").append(t.val); preOrder(t.left,sb); preOrder(t.right,sb); } // Decodes your encoded data to tree. public TreeNode deserialize(String data) { if(data.length()==0){return null;} String s[]=data.split("#",-1); Queue<Integer> q=new LinkedList<>(); for(int i=1;i<s.length;i++){q.add(Integer.parseInt(s[i]));} return reFormBST(q,-1,(int)1e5); } public TreeNode reFormBST(Queue<Integer> q,int min,int max){ if(q.size()==0||q.peek()>=max||q.peek()<=min){return null;} int a=q.poll(); return new TreeNode(a,reFormBST(q,min,a),reFormBST(q,a,max)); } }
222. 完全二叉树的节点个数
-
题目描述
-
题解
class Solution { public int countNodes(TreeNode root) { int res=0; if(root==null) return res; Queue<TreeNode> queue=new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()){ int size=queue.size(); while(size>0){ res++; TreeNode node=queue.poll(); if(node.left!=null) queue.offer(node.left); if(node.right!=null) queue.offer(node.right); size--; } } return res; } }
437. 路径总和 III
-
题目描述
-
题解
class Solution { public int pathSum(TreeNode root, int targetSum) { if(root==null) return 0; //在以root开头 叶子结点结束的基础上 遍历计算所有节点 return pathSumWithRoot(root,targetSum)+pathSum(root.left,targetSum)+pathSum(root.right,targetSum); } public int pathSumWithRoot(TreeNode node,int sum){ if(node==null) return 0; int res=0; if(node.val==sum) res++; res+=pathSumWithRoot(node.left,sum-node.val)+pathSumWithRoot(node.right,sum-node.val); return res; } }
701. 二叉搜索树中的插入操作
-
题目描述
-
题解
class Solution { public TreeNode insertIntoBST(TreeNode root, int val) { if(root==null) return new TreeNode(val); TreeNode pre=null; TreeNode cur=root; while(cur!=null){ pre=cur; if(cur.val>val){ cur=cur.left; }else if(cur.val<val){ cur=cur.right; } } TreeNode addNode=new TreeNode(val); if(pre.val>val){ pre.left=addNode; }else{ pre.right=addNode; } return root; } }
深度/广度优先搜索
200. 岛屿数量
-
题目描述
-
题解
- 思路:遍历岛这个二维数组,如果当前数为1,则进入感染函数并将岛个数+1
- 感染函数:其实就是一个递归标注的过程,它会将所有相连的1都标注成2。为什么要标注?这样就避免了遍历过程中的重复计数的情况,一个岛所有的1都变成了2后,遍历的时候就不会重复遍历了
class Solution { public int numIslands(char[][] grid) { int islandNum = 0; for(int i = 0; i < grid.length; i++){ for(int j = 0; j < grid[0].length; j++){ if(grid[i][j] == '1'){ infect(grid, i, j); islandNum++; } } } return islandNum; } //感染函数 public void infect(char[][] grid, int i, int j){ if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != '1'){ return; } grid[i][j] = '2'; infect(grid, i + 1, j); infect(grid, i - 1, j); infect(grid, i, j + 1); infect(grid, i, j - 1); } }
98. 验证二叉搜索树
-
题目描述
-
题解
class Solution { public boolean isValidBST(TreeNode root) { if(root==null) return true; Stack<TreeNode> stack = new Stack<>(); stack.push(root); Integer preNum = null; while (!stack.isEmpty()) { TreeNode node=stack.peek(); if(node!=null){ stack.pop(); if(node.right!=null) stack.push(node.right); stack.push(node); stack.push(null); if(node.left!=null) stack.push(node.left); }else{ stack.pop(); node = stack.peek(); if(preNum!=null && node.val<=preNum) return false; preNum=node.val; stack.pop(); } } return true; } }
110. 平衡二叉树
-
题目描述
-
题解
class Solution { public boolean isBalanced(TreeNode root) { return getHeight(root)==-1?false:true; } public int getHeight(TreeNode node){ if(node==null) return 0; int left=getHeight(node.left); if(left==-1) return -1; int right=getHeight(node.right); if(right==-1) return -1; if(Math.abs(left-right)>1){ return -1; }else{ return Math.max(left,right)+1; } } }
105. 从前序与中序遍历序列构造二叉树
-
题目描述
-
题解
class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { return traversal(preorder,0,preorder.length,inorder,0,inorder.length); } public TreeNode traversal(int[] preorder,int preStart,int preEnd,int[] inorder,int inStart,int inEnd){ if(inEnd-inStart<1) return null; if(inEnd-inStart==1) return new TreeNode(inorder[inStart]); //前序第一个节点就是root节点 int rootVal=preorder[preStart]; TreeNode res=new TreeNode(rootVal); //根据rootval 找到再中序中的位置 int rootIndex=0; for(int i=inStart;i<inEnd;i++){ if(inorder[i]==rootVal){ rootIndex=i; break; } } res.left=traversal(preorder,preStart+1,preStart+1+rootIndex-inStart,inorder,inStart,rootIndex);; res.right=traversal(preorder,preStart+rootIndex-inStart+1,preEnd,inorder,rootIndex+1,inEnd); return res; } }
679. 24 点游戏
-
题目描述
-
题解
/** dfs 初始有4个数,任意挑选两个数做加减乘除得到一个新数 则原问题变为3个数能否凑成24。依次类推递归直到剩1个数是否为24 */ class Solution { public boolean judgePoint24(int[] cards) { double[] a = new double[4]; for (int i = 0; i < 4; i++) a[i] = (double)cards[i]; return dfs(a); } private boolean dfs(double[] cards) { if (cards.length == 1) { return cards[0] > 23.99 && cards[0] < 24.01; } int n = cards.length; // 选出两个数 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) continue; // 除这两个数以外的数加入数组 double[] nextcards = new double[n-1]; int p = 0; for (int k = 0; k < n; k++) { if (k == i || k == j) continue; nextcards[p++] = cards[k]; } boolean res = false; nextcards[p] = cards[i] + cards[j]; res |= dfs(nextcards); if (res) return true; nextcards[p] = cards[i] - cards[j]; res |= dfs(nextcards); if (res) return true; nextcards[p] = cards[i] * cards[j]; res |= dfs(nextcards); if (res) return true; nextcards[p] = cards[i] / cards[j]; res |= dfs(nextcards); if (res) return true; } } return false; } }
129. 求根节点到叶节点数字之和
-
题目描述
-
题解
class Solution { List<Integer> path = new ArrayList<>(); int res = 0; public int sumNumbers(TreeNode root) { // 如果节点为0,那么就返回0 if (root == null) return 0; // 首先将根节点放到集合中 path.add(root.val); // 开始递归 recur(root); return res; } public void recur(TreeNode root){ if (root.left == null && root.right == null) { // 当是叶子节点的时候,开始处理 res += listToInt(path); return; } if (root.left != null){ // 注意有回溯 path.add(root.left.val); recur(root.left); path.remove(path.size() - 1); } if (root.right != null){ // 注意有回溯 path.add(root.right.val); recur(root.right); path.remove(path.size() - 1); } return; } public int listToInt(List<Integer> path){ int sum = 0; for (Integer num:path){ // sum * 10 表示进位 sum = sum * 10 + num; } return sum; } }
103. 二叉树的锯齿形层序遍历
-
题目描述
-
题解
class Solution { public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> res=new ArrayList<>(); if(root==null) return res; Deque<TreeNode> queue=new LinkedList<>(); queue.offer(root); int flag=0; while(!queue.isEmpty()){ int size=queue.size(); List<Integer> temp=new ArrayList<>(); if(flag%2==0){ for(int i=0;i<size;i++){ TreeNode node=queue.poll(); temp.add(node.val); if(node.left!=null) queue.offer(node.left); if(node.right!=null) queue.offer(node.right); } }else{ for(int i=0;i<size;i++){ TreeNode node=queue.pollLast(); temp.add(node.val); if(node.right!=null) queue.offerFirst(node.right); if(node.left!=null) queue.offerFirst(node.left); } } res.add(new ArrayList(temp)); flag++; } return res; } }
102. 二叉树的层序遍历
-
题目描述
-
题解
class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); if(root==null) return res; Deque<TreeNode> queue=new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()){ int size = queue.size(); List<Integer> temp = new ArrayList<>(); for (int i = 0; i < size; i++) { TreeNode node = queue.poll(); temp.add(node.val); if(node.left!=null) queue.offer(node.left); if(node.right!=null) queue.offer(node.right); } res.add(temp); } return res; } }
133. 克隆图
-
题目描述
-
题解
class Solution { public Node cloneGraph(Node node) { if (node == null) return null; Deque<Node> q = new LinkedList<>(); q.offer(node); Map<Integer, Node> map = new HashMap<>(); map.put(node.val, new Node(node.val)); while (!q.isEmpty()) { Node source = q.poll(); List<Node> nodes = source.neighbors; Node dest = map.get(source.val); for (Node n: nodes) { if (!map.containsKey(n.val)) { q.offer(n); map.put(n.val, new Node(n.val)); } dest.neighbors.add(map.get(n.val)); } } return map.get(node.val); } }
863. 二叉树中所有距离为 K 的结点
-
题目描述
-
题解
class Solution { Map<Integer, TreeNode> parents = new HashMap<Integer, TreeNode>(); List<Integer> ans = new ArrayList<Integer>(); public List<Integer> distanceK(TreeNode root, TreeNode target, int k) { // 从 root 出发 DFS,记录每个结点的父结点 findParents(root); // 从 target 出发 DFS,寻找所有深度为 k 的结点 findAns(target, null, 0, k); return ans; } public void findParents(TreeNode node) { if (node.left != null) { parents.put(node.left.val, node); findParents(node.left); } if (node.right != null) { parents.put(node.right.val, node); findParents(node.right); } } public void findAns(TreeNode node, TreeNode from, int depth, int k) { if (node == null) { return; } if (depth == k) { ans.add(node.val); return; } if (node.left != from) { findAns(node.left, node, depth + 1, k); } if (node.right != from) { findAns(node.right, node, depth + 1, k); } if (parents.get(node.val) != from) { findAns(parents.get(node.val), node, depth + 1, k); } } }
116. 填充每个节点的下一个右侧节点指针
-
题目描述
-
题解
class Solution { public Node connect(Node root) { if(root==null) return root; Queue<Node> queue=new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()){ int size=queue.size(); Node cur=queue.poll(); if(cur.left!=null) queue.offer(cur.left); if(cur.right!=null) queue.offer(cur.right); for(int i=1;i<size;i++){ Node next=queue.poll(); if(next.left!=null) queue.offer(next.left); if(next.right!=null) queue.offer(next.right); cur.next=next; cur=next; } } return root; } }
递归
124. 二叉树中的最大路径和
-
题目描述
-
题解
class Solution { int res = Integer.MIN_VALUE; public int maxPathSum(TreeNode root) { /** 对于任意一个节点, 如果最大和路径包含该节点, 那么只可能是两种情况: 1. 其左右子树中所构成的和路径值较大的那个加上该节点的值后向父节点回溯构成最大路径 2. 左右子树都在最大路径中, 加上该节点的值构成了最终的最大路径 **/ getMax(root); return res; } private int getMax(TreeNode r) { if(r == null) return 0; //如果子树路径和为负则应当置0表示最大路径不包含子树 int left = Math.max(0, getMax(r.left)); int right = Math.max(0, getMax(r.right)); //判断在该节点包含左右子树的路径和是否大于当前最大路径和 res = Math.max(res, r.val + left + right); return Math.max(left, right) + r.val; } }
98. 验证二叉搜索树
-
题目描述
-
题解
class Solution { public boolean isValidBST(TreeNode root) { if(root==null) return true; Stack<TreeNode> stack = new Stack<>(); stack.push(root); Integer preNum = null; while (!stack.isEmpty()) { TreeNode node=stack.peek(); if(node!=null){ stack.pop(); if(node.right!=null) stack.push(node.right); stack.push(node); stack.push(null); if(node.left!=null) stack.push(node.left); }else{ stack.pop(); node = stack.peek(); if(preNum!=null && node.val<=preNum) return false; preNum=node.val; stack.pop(); } } return true; } }class Solution { long pre = Long.MIN_VALUE; public boolean isValidBST(TreeNode root) { if(root==null){ return true; } if(!isValidBST(root.left)){ return false; } if(root.val<=pre){ return false; } pre=root.val; return isValidBST(root.right); } }
21. 合并两个有序链表
-
题目描述
-
题解
class Solution { public ListNode mergeTwoLists(ListNode list1, ListNode list2) { if(list1==null) return list2; if(list2==null) return list1; if(list1.val>list2.val){ list2.next=mergeTwoLists(list1,list2.next); return list2; }else{ list1.next=mergeTwoLists(list1.next,list2); return list1; } } }
110. 平衡二叉树
-
题目描述
-
题解
class Solution { public boolean isBalanced(TreeNode root) { return getHeight(root)==-1?false:true; } public int getHeight(TreeNode node){ if(node==null) return 0; int left=getHeight(node.left); if(left==-1) return -1; int right=getHeight(node.right); if(right==-1) return -1; if(Math.abs(left-right)>1){ return -1; }else{ return Math.max(left,right)+1; } } }
24. 两两交换链表中的节点
-
题目描述

-
题解
class Solution { public ListNode swapPairs(ListNode head) { if(head==null) return head; ListNode dummy=new ListNode(-1); dummy.next=head; ListNode cur=head; ListNode pre=dummy; while(cur!=null && cur.next!=null){ ListNode temp=cur.next.next; pre.next=cur.next; cur.next.next=cur; cur.next=temp; pre=cur; cur=cur.next; } return dummy.next; } }
104. 二叉树的最大深度
-
题目描述
-
题解
class Solution { public int maxDepth(TreeNode root) { if(root==null) return 0; return Math.max(maxDepth(root.left),maxDepth(root.right))+1; } }
109. 有序链表转换二叉搜索树
-
题目描述
-
题解
class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null) return null; else if(head.next == null) return new TreeNode(head.val); ListNode pre = head; ListNode p = pre.next; ListNode q = p.next; //找到链表的中点p while(q!=null && q.next!=null){ pre = pre.next; p = pre.next; q = q.next.next; } //将中点左边的链表分开 pre.next = null; TreeNode root = new TreeNode(p.val); root.left = sortedListToBST(head); root.right = sortedListToBST(p.next); return root; } }
108. 将有序数组转换为二叉搜索树
-
题目描述
-
题解
class Solution { //左右等分建立左右子树,中间节点作为子树根节点,递归该过程 public TreeNode sortedArrayToBST(int[] nums) { return traversal(nums,0,nums.length-1); } public TreeNode traversal(int[] nums,Integer start,Integer end){ if(start>end) return null; int mid=start+(end-start)/2; TreeNode res=new TreeNode(nums[mid]); res.left=traversal(nums,start,mid-1); res.right=traversal(nums,mid+1,end); return res; } }
面试题 08.06. 汉诺塔问题
-
题目描述
-
题解
class Solution { public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) { int n = A.size(); move(n, A, B, C); } public void move(int n, List<Integer> A, List<Integer> B, List<Integer> C) { if (n == 1) { C.add(A.remove(A.size() - 1)); return; } //将A上面n-1个通过C移到B move(n - 1, A, C, B); //将A最后一个移到C //这时,A空了 C.add(A.remove(A.size() - 1)); //将B上面n-1个通过空的A移到C move(n - 1, B, A, C); } }