剑指Offer题解
剑指 Offer 03. 数组中重复的数字
思路一:哈希表O(n)
class Solution {public int findRepeatDocument(int[] documents) {int len = documents.length;int[] arr = new int[100010];for(int i = 0; i < len; i ++ ) {arr[documents[i]] ++;if (arr[documents[i]] == 2) {return documents[i];}}return 0;}
}
思路二: 原地交换O(n)
class Solution {public int findRepeatDocument(int[] documents) {int len = documents.length;for(int i = 0; i < len; i ++ ){while (documents[i] != i) {if(documents[i] == documents[documents[i]]) {return documents[i];}int t = documents[i];documents[i] = documents[t];documents[t] = t;}}return -1;}
}
剑指 Offer 04. 二维数组中的查找
思路一:单调性扫描O(n+m)
class Solution {public boolean findTargetIn2DPlants(int[][] plants, int target) {int len1 = plants.length;if (len1 <= 0) return false;int len2 = plants[0].length;if (len2 <= 0) return false;for(int i = len1 - 1, j = 0; ;) {if(plants[i][j] <target) {j ++;} else if(plants[i][j] > target){i --;} else {return true;}if(i < 0 || j >= len2) {break;}}return false;}
}
思路二:二分O(nlogn)
class Solution {public boolean findTargetIn2DPlants(int[][] plants, int target) {int len1 = plants.length;if (len1 <= 0) return false;int len2 = plants[0].length;if (len2 <= 0) return false;for(int i = 0; i < len1; i ++ ) {if (midf(plants, i, target)) {return true;}}return false;}public boolean midf(int[][] plants, int i, int target) {int l = 0;int r = plants[i].length - 1;while(l < r) {int mid = l + r >> 1;if(plants[i][mid] >= target) {r = mid;} else {l = mid + 1;}}if(plants[i][l] == target) return true;return false;}
}
剑指 Offer 05. 替换空格
思路一:遍历添加O(n)
class Solution {public String pathEncryption(String path) {StringBuilder sb = new StringBuilder();char[] c = path.toCharArray();for(char ct : c) {if(ct == '.') sb.append(' ');else sb.append(ct);}return sb.toString();}
}
思路二:正则表达式替换O(n)
class Solution {public String pathEncryption(String path) {return path.replaceAll("\\.", " ");}
}
剑指 Offer 06. 从尾到头打印链表
思路一:辅助栈法O(n)
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public int[] reverseBookList(ListNode head) {Stack<Integer> stack = new Stack();int[] q;ListNode dummy = head;int length = 0;while(dummy != null) {stack.push(dummy.val);dummy = dummy.next;length ++;}q = new int[length];for(int i = 0; i < length; i++ ) {q[i] = stack.pop();}return q;}
}
思路二:递归法O(n)
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {ArrayList<Integer> temp = new ArrayList();public int[] reverseBookList(ListNode head) {recur(head); int[] res = new int[temp.size()];for(int i = 0; i < res.length; i ++) {res[i] = temp.get(i);} return res;}void recur(ListNode head) {if(head == null) return;recur(head.next);temp.add(head.val);}
}
思路三:遍历反转法O(n)
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {ArrayList<Integer> list = new ArrayList();public int[] reverseBookList(ListNode head) {int length = 0;ListNode dummy = head;while(dummy != null) {list.add(dummy.val);dummy = dummy.next;length ++;}Collections.reverse(list);int[] q = new int[list.size()];for(int i = 0; i < q.length; i ++) {q[i] = list.get(i);}return q;}
}
剑指 Offer 07. 重建二叉树
思路一:递归法O(n)
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/
class Solution {int[] preorder;HashMap<Integer, Integer> hmap = new HashMap();public TreeNode deduceTree(int[] preorder, int[] inorder) {this.preorder = preorder;for(int i = 0; i < inorder.length; i ++ ) {hmap.put(inorder[i], i);}return recur(0, 0, inorder.length - 1);}TreeNode recur(int root, int left, int right) {if(left > right) return null;TreeNode node = new TreeNode(preorder[root]);int i = hmap.get(preorder[root]);node.left = recur(root + 1, left, i - 1);node.right = recur(root + i - left + 1, i + 1, right);return node;}
}
剑指 Offer 08. 二叉树的下一个结点
思路一:中序遍历法O(n)
import java.util.*;
public class Solution {ArrayList<TreeLinkNode> nodes = new ArrayList<>();public TreeLinkNode GetNext(TreeLinkNode pNode) {// 获取根节点TreeLinkNode root = pNode;while(root.next != null) root = root.next;// 中序遍历打造nodesInOrder(root);// 进行匹配int n = nodes.size();for(int i = 0; i < n - 1; i++) {TreeLinkNode cur = nodes.get(i);if(pNode == cur) {return nodes.get(i+1);}}return null;}// 中序遍历void InOrder(TreeLinkNode root) {if(root != null) {InOrder(root.left);nodes.add(root);InOrder(root.right);}}
}
思路二:分类直接查找法O(n)
import java.util.*;
public class Solution {public TreeLinkNode GetNext(TreeLinkNode pNode) {// 情况一if(pNode.right != null) {TreeLinkNode rchild = pNode.right;// 一直找到右子树的最左下的结点为返回值while(rchild.left != null) rchild = rchild.left; return rchild;}// 情况二if(pNode.next != null && pNode.next.left == pNode) {return pNode.next;}// 情况三if(pNode.next != null) {TreeLinkNode ppar = pNode.next;// 沿着左上一直爬树,爬到当前结点是其父节点的左自己结点为止while(ppar.next != null && ppar.next.right == ppar) ppar = ppar.next; return ppar.next;}return null;}
}
剑指 Offer 09. 用两个栈实现队列
思路:栈模拟O(n)
class CQueue {Stack<Integer> stack1;Stack<Integer> stack2;public CQueue() {stack1 = new Stack();stack2 = new Stack();}public void appendTail(int value) {stack1.push(value);}public int deleteHead() {if (stack2.isEmpty()) {while(!stack1.isEmpty()) {stack2.push(stack1.pop());}}return stack2.isEmpty() ? -1 : stack2.pop();}
}/*** Your CQueue object will be instantiated and called as such:* CQueue obj = new CQueue();* obj.appendTail(value);* int param_2 = obj.deleteHead();*/
剑指 Offer 10- I. 斐波那契数列
思路一:暴力递归O(2^n) 超出时间限制
class Solution {public int fib(int n) {if(n < 2) return n;return (fib(n - 1) + fib(n - 2)) % 1000000007;}
}
**思路二:记忆化递归O(n) **
class Solution {public int fib(int n) {if(n < 2) return n;int[] fib = new int[n + 1];fib[0] = 0;fib[1] = 1;for(int i = 2; i <= n; i ++) {fib[i] = (fib[i - 1] + fib[i - 2]) % 1000000007;}return fib[n];}
}
**思路三:动态规划O(n) **
class Solution {public int fib(int n) {if (n < 2) return n;int a = 0;int b = 1;int sum;for(int i = 0; i < n; i ++) {sum = (a + b) % 1000000007;a = b;b = sum;}// i =0 时, a就是fib[1]的值return a;}
}
剑指 Offer 10- II. 青蛙跳台阶问题
**思路一:记忆化递归O(n) **
class Solution {public int trainWays(int num) {if(num < 2) return 1;int[] fib = new int[num + 1];fib[0] = 1;fib[1] = 1;for(int i = 2; i <= num; i++ ){fib[i] = (fib[i - 1] + fib[i - 2]) % 1000000007;}return fib[num];}
}
思路二:动态规划O(n)
class Solution {public int trainWays(int num) {int a = 0;int b = 1;int sum;for(int i = 0; i < num; i ++) {sum = (a + b) % 1000000007;a = b;b = sum;}//i= 0时,b就是fib[1]的值,和上一题的区别就是num = 0时,有一种方法return b;}
}