剑指 Offer(第 2 版)所有题目答案 突击面试
剑指Offer第二版所有题目,自己编写整理笔记,保证能够运行!
题库链接
https://leetcode.cn/problem-list/xb9nqhhg/
数组中重复的数字
class Solution {
public int findRepeatNumber(int[] nums) {
Set<Integer> dic = new HashSet<>();
for (int num : nums) {
if (dic.contains(num)) return num;
dic.add(num);
}
return -1;
}
}
二维数组中的查找
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
int i = matrix.length-1;
int j = 0;
while (i >= 0 && j < matrix[0].length) {
if (matrix[i][j] > target) i--;
else if (matrix[i][j] <target) j++;
else return true;
}
return false;
}
}
替换空格
class Solution {
public String replaceSpace(String s) {
StringBuilder res = new StringBuilder();
for (Character c : s.toCharArray()) {
if (c == ' ') {
res.append("%20");
} else {
res.append(c);
}
}
return res.toString();
}
}
从尾到头打印链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
LinkedList<Integer> stack = new LinkedList<Integer>();
while (head != null) {
stack.addLast(head.val);
head = head.next;
}
int[] res = new int[stack.size()];
for (int i = 0; i < res.length; i++) {
res[i] = stack.removeLast();
}
return res;
}
}
不使用栈
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
ListNode node = head;
int count = 0;
while (node != null) {
++count;
node = node.next;
}
int[] nums = new int[count];
node = head;
for (int i = count - 1; i >= 0; i--) {
nums[i] = node.val;
node = node.next;
}
return nums;
}
}
重建二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length <= 0) return null;
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
TreeNode root = f(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
return root;
}
TreeNode f(int[] preorder, int l1, int r1, int[] inorder, int l2, int r2) {
if (l1 > r1 && l2 > r2) return null;
TreeNode root = new TreeNode(preorder[l1]);
int i = map.get(preorder[l1]);
root.left = f(preorder, l1 + 1, l1 + (i - l2), inorder, l2, i - 1);
root.right = f(preorder, l1 + (i - l2) + 1, r1, inorder, i + 1, r2);
return root;
}
}
用两个栈实现队列
class CQueue {
Stack<Integer> st1;
Stack<Integer> st2;
public CQueue() {
st1 = new Stack<>();
st2 = new Stack<>();
}
public void appendTail(int value) {
st1.push(value);
}
public int deleteHead() {
if (!st2.isEmpty()) {
return st2.pop();
}
if (!st1.isEmpty()) {
while (!st1.isEmpty()) {
st2.push(st1.pop());
}
return st2.pop();
}
return -1;
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
斐波那契数列
class Solution {
public int fib(int n) {
int a = 0, b = 1, sum;
for (int i = 1; i <= n; i++) {
sum = (a + b) % 1000000007;
a =b;
b = sum;
}
return a;
}
}
青蛙跳台阶问题
class Solution {
public int numWays(int n) {
int[] dp = new int[n + 2];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = (dp[i - 1] + dp[i - 2])%1000000007;
}
return dp[n];
}
}
旋转数组的最小数字
class Solution {
public int minArray(int[] numbers) {
int l = 0, r = numbers.length - 1;
while (l < r) {
int mid = l + r >> 1;
if (numbers[mid] < numbers[r]) r = mid;
else if (numbers[mid] > numbers[r]) l = mid + 1;
else r -= 1;
}
return numbers[l];
}
}
矩阵中的路径
class Solution {
public boolean exist(char[][] board, String word) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (dfs(board, word, 0, i, j)) return true;
}
}
return false;
}
int[] dx = new int[]{1,0,0,-1};
int[] dy = new int[]{0,1,-1,0};
boolean dfs(char[][] board, String word, int u, int x, int y) {
if (board[x][y] != word.charAt(u)) return false;
if (u == word.length() - 1) return true;
char t = board[x][y];
board[x][y] = '.';
for (int i = 0; i < 4; i++) {
int xx = x + dx[i], yy = y + dy[i];
if (xx < 0 || xx > board.length - 1 || yy < 0 || yy > board[0].length - 1 || board[xx][yy] == '.') continue;
if (dfs(board, word, u + 1, xx, yy)) return true;
}
board[x][y] = t;
return false;
}
}
剪绳子
dp
class Solution {
public int cuttingRope(int n) {
int[] dp = new int[n + 1];
dp[2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 2; j < i; j ++) {
dp[i] = Math.max(dp[i], Math.max(j * dp[i - j], j * (i - j)));
}
}
return dp[n];
}
}
class Solution {
public int cuttingRope(int n) {
if (n < 4) return n - 1;
int res = 1;
while ( n > 4) {
res = res * 3;
n -= 3;
}
return res * n;
}
}
剪绳子 II
dp
import java.math.BigInteger;
class Solution {
public int cuttingRope(int n) {
//大数
BigInteger[] dp = new BigInteger[n + 1];
Arrays.fill(dp, BigInteger.valueOf(1));
for (int i = 3; i <= n; i++) {
for (int j = 1; j < i; j++){
dp[i] = dp[i].max(BigInteger.valueOf(j * ((i - j))).max(dp[i - j].multiply(BigInteger.valueOf(j))));
}
}
return dp[n].mod(BigInteger.valueOf(1000000007)).intValue();
}
}
贪心
import java.math.BigInteger;
class Solution {
public int cuttingRope(int n) {
if (n <= 3) return n- 1;
long res = 1L;
long mod =1000000007;
while (n > 4) {
res=res*3%mod;
n-=3;
}
return (int)( res * n % mod);
}
}
二进制中1的个数
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int res = 0;
for (int i = 0; i < 32; i++) {
if((n & (1 << i)) != 0) {
res ++;
}
}
return res;
}
}
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int sum = 0;
while (n != 0) {
n = n & (n - 1);
sum++;
}
return sum;
}
}
数值的整数次方
class Solution {
public double myPow(double x, int n) {
double res = 1;
long y = n;
if (y < 0) {
y = -y;
x = 1/ x;
}
while (y > 0) {
if (y % 2 == 1) {
res = res * x;
}
x = x * x;
y = y / 2;
}
return res ;
}
}
打印从1到最大的n位数
class Solution {
public int[] printNumbers(int n) {
int m = (int)Math.pow(10, n) - 1;
int[] res = new int[m];
for (int i = 0; i < m; i++){
res[i] = i + 1;
}
return res;
}
}
格雷编码
class Solution {
public List<Integer> grayCode(int n) {
/*
N = 3;
000 0
001 1
011 3
010 2
110 6
111 7
101 5
100 4
*/
List<Integer> res = new ArrayList<>();
res.add(0);
if (n == 0) return res;
int c = 1;
while (c <= n) {
int index = res.size() - 1;
while (index >= 0) {
res.add(res.get(index--) + (int)Math.pow(2, c - 1));
}
c++;
}
return res;
}
}
删除链表的节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head.val == val) return head.next;
ListNode pre = head, cur = head.next;
while (cur != null && cur.val != val) {
pre = cur;
cur = cur.next;
}
if (cur != null) pre.next = cur.next;
return head;
}
}
正则表达式匹配
class Solution {
public boolean isMatch(String s, String p) {
int n = s.length();
int m = p.length();
boolean[][] dp = new boolean[n + 1][m + 1];
dp[0][0] = true;
for (int i = 0; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i][j- 2];
if (matches(s, p, i, j - 1)) {
dp[i][j] = dp[i][j] || dp[i - 1][j];
}
} else {
if (matches(s, p, i, j)) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
}
return dp[n][m];
}
public boolean matches(String s, String p, int i, int j) {
if (i == 0) return false;
if (p.charAt(j - 1)=='.') return true;
return s.charAt(i - 1) == p.charAt(j - 1);
}
}
表示数值的字符串
class Solution {
public boolean isNumber(String s) {
if (s == null || s.length() == 0) return false;
s = s.trim(); //去掉首位的空格
boolean numFlag = false; //是否出现数字
boolean dotFlag = false;//是否出现小数点
boolean eFlag = false;//是否出现e
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) >= '0' && s.charAt(i) <='9') { //判断为出现数字
numFlag = true;
}
else if (s.charAt(i) == '.' && dotFlag == false && !eFlag) { //出现为小数点,且只能出现一次
dotFlag = true;
}
else if ((s.charAt(i) == 'e' || s.charAt(i) == 'E') && eFlag == false && numFlag == true) {
eFlag = true;
numFlag = false;
}
else if ((s.charAt(i) == '+' || s.charAt(i) == '-') && (i == 0 ||s.charAt(i - 1) == 'e' || s.charAt(i - 1) == 'E')){ //如果是+-号
continue;
} else {
return false;
}
}
return numFlag;
}
}
调整数组顺序使奇数位于偶数前面
class Solution {
public int[] exchange(int[] nums) {
if (nums == null || nums.length == 0) return nums;
int l = 0, r = nums.length - 1;
while (l < r) {
while (l < r && nums[l] % 2 == 1) l++;
while (l < r && nums[r] % 2 == 0) r--;
int temp = nums[l];
nums[l] =nums[r];
nums[r] = temp;
}
return nums;
}
}
链表中倒数第k个节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if (head == null) return null;
ListNode fast = head;
ListNode slow = head;
for (int i = 0; i < k; i++) {
if (fast == null) return null;
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
反转链表
递归
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode temp = reverseList(head.next);
head.next.next = head;
head.next = null;
return temp;
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode cur = head, pre = null;
while (cur != null) {
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
合并两个排序的链表
迭代法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode merge = new ListNode(0);
ListNode temp = merge;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
temp.next = l1;
l1 = l1.next;
} else {
temp.next = l2;
l2 = l2.next;
}
temp = temp.next;
}
temp.next = l1 == null ? l2 : l1;
return merge.next;
}
}
递归法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
else if (l2 == null) return l1;
else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
树的子结构
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A == null || B == null) return false;
if (isTree(A, B)) return true;
else if (isSubStructure(A.left, B) || isSubStructure(A.right, B)) return true;
return false;
}
boolean isTree(TreeNode TA, TreeNode TB) {
if (TB == null) return true;
if (TA == null) return false;
if (TA.val != TB.val) return false;
return isTree(TA.left, TB.left) && isTree(TA.right, TB.right);
}
}
二叉树的镜像
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null) return root;
TreeNode left = null;
TreeNode right = null;
if (root.left != null) left = mirrorTree(root.left);
if (root.right != null) right =mirrorTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
对称的二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null || (root.left == null && root.right == null)) return true;
return f(root.left, root.right);
}
boolean f(TreeNode left , TreeNode right) {
if (left == null && right == null) return true;
if (left == null || right == null) return false;
if (left.val != right.val) return false;
return f(left.left, right.right) && f(left.right, right.left);
}
}
顺时针打印矩阵
class Solution {
public int[] spiralOrder(int[][] matrix) {
if (matrix.length == 0) return new int[0];
int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1;
int[] res = new int[(r +1) * (b + 1)];
int k = 0;
while (true) {
//从左向右
for (int i = l; i <= r; i++) {
res[k++] = matrix[t][i];
}
if (++t > b) break;
//从上往下
for (int i = t; i <= b; i++) {
res[k++] = matrix[i][r];
}
if (l > --r) break;
//从右往左
for (int i = r; i >= l; i--) {
res[k++] = matrix[b][i];
}
if (t > --b) break;
//从下往上
for (int i = b; i >= t; i--) {
res[k++] = matrix[i][l];
}
if (++l > r) break;
}
return res;
}
}
包含min函数的栈
class MinStack {
Stack<Integer> stack1;
Stack<Integer> stack2;
/** initialize your data structure here. */
public MinStack() {
this.stack1 = new Stack();
this.stack2 = new Stack();
}
public void push(int x) {
stack1.push(x);
if (stack2.isEmpty() || stack2.peek().intValue() >= x) {
stack2.push(x);
}
}
public void pop() {
if (!stack1.isEmpty()) {
if (stack1.peek().intValue() == stack2.peek().intValue()) {
stack2.pop();
}
stack1.pop();
}
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.min();
*/
栈的压入、弹出序列
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
if (pushed.length == 0 || pushed == null) return true;
Stack<Integer> stack = new Stack<>();
int k = 0;
for (int i = 0; i < pushed.length; i++) {
stack.push(pushed[i]);
while (!stack.isEmpty() && stack.peek() == popped[k]) {
k++;
stack.pop();
}
}
return stack.isEmpty();
}
}
从上到下打印二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
if (root == null) {
return new int[0];
}
Queue<TreeNode> queue = new LinkedList<>();
List<Integer> res = new ArrayList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
res.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
int[] arr = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
arr[i] = res.get(i);
}
return arr;
}
}
从上到下打印二叉树 II
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
int k = q.size();
List<Integer> arr = new ArrayList<>();
while (k-- >0) {
TreeNode node = q.peek();
if (node.left != null) q.add(node.left);
if (node.right != null) q.add(node.right);
TreeNode kk = q.poll();
arr.add(kk.val);
}
res.add(arr);
}
return res;
}
}
从上到下打印二叉树 III
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
int num = 1;//判断奇数偶数 奇数就从左往右;
while (!q.isEmpty()) {
int k = q.size();
LinkedList<Integer> cnt = new LinkedList<>();
while (k-- >0) {
TreeNode node = q.poll();
if (num % 2 == 1) {
cnt.add(node.val);
if (node.left != null) q.add(node.left);
if (node.right != null) q.add(node.right);
} else {
cnt.addFirst(node.val);
if (node.left != null) q.add(node.left);
if (node.right != null) q.add(node.right);
}
}
res.add(cnt);
num ++ ;
}
return res;
}
}
二叉搜索树的后序遍历序列
class Solution {
public boolean verifyPostorder(int[] postorder) {
return f(postorder, 0, postorder.length - 1);
}
boolean f(int[] postorder, int l, int r) {
if (l >= r) return true;
int p = l;
while (postorder[p] < postorder[r]) p++;
int m = p;
//左子树为l m - 1, m r - 1;
while (postorder[p] > postorder[r]) p++;
return p==r && f(postorder, l, m - 1) && f(postorder, m, r - 1);
}
}
使用栈
class Solution {
public boolean verifyPostorder(int[] postorder) {
Stack<Integer> stack = new Stack<>();
int root = Integer.MAX_VALUE;
for (int i = postorder.length - 1; i >= 0; i--) {
int cur = postorder[i];
while (!stack.isEmpty() && cur < stack.peek()) {
root = stack.pop();
}
if (cur > root) return false;
stack.add(cur);
}
return true;
}
}
二叉树中和为某一值的路径
/**
* 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 {
List<List<Integer>> res = new LinkedList<>();
Deque<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int target) {
dfs(root, target);
return res;
}
void dfs(TreeNode root, int target) {
if (root == null) return ;
path.offerLast(root.val);
target -= root.val;
if (target == 0 && root.left == null && root.right == null) {
res.add(new LinkedList<Integer>(path));
}
dfs(root.left, target);
dfs(root.right, target);
target += root.val;
path.pollLast();
}
}
复杂链表的复制
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
//复制节点
Node cur = head;
while (cur != null) {
Node next = cur.next;
cur.next = new Node(cur.val);
cur.next.next = next;
cur = next;
}
//复制random节点
cur = head;
while (cur != null) {
Node curNew = cur.next;
curNew.random = cur.random == null ? null : cur.random.next;
cur = cur.next.next;
}
//拆分
Node newHead = head.next;
cur = head;
Node curNew = head.next;
while (cur != null) {
cur.next = cur.next.next;
cur = cur.next;
curNew.next = cur == null ? null : cur.next;
curNew = curNew.next;
}
return newHead;
}
}
二叉搜索树与双向链表
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
public Node treeToDoublyList(Node root) {
if (root == null) return null;
Queue<Node> q = new LinkedList<>();
inordered(q, root);
Node head = q.poll();
Node pre = head;
while (!q.isEmpty()) {
Node cur = q.poll();
pre.right = cur;
cur.left = pre;
pre = cur;
}
pre.right = head;
head.left = pre;
return head;
}
public void inordered(Queue q, Node root) {
if (root == null) return ;
inordered(q, root.left);
q.add(root);
inordered(q, root.right);
}
}
序列化二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if (root == null) return "[]";
StringBuilder res = new StringBuilder("[");
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (node!=null) {
res.append(node.val + ",");
q.add(node.left);
q.add(node.right);
}
else res.append("null,");
}
res.deleteCharAt(res.length() - 1);
res.append("]");
return res.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if (data.equals("[]")) {
return null;
}
String[] vals = data.substring(1, data.length() - 1).split(",");
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
int i = 1;
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (!vals[i].equals("null")) {
node.left = new TreeNode(Integer.parseInt(vals[i]));
q.add(node.left);
}
i++;
if (!vals[i].equals("null")) {
node.right = new TreeNode(Integer.parseInt(vals[i]));
q.add(node.right);
}
i++;
}
return root;
}
}
// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));
数组中出现次数超过一半的数字
class Solution {
public int majorityElement(int[] nums) {
int x= 0, votes = 0, count = 0;
for (int num : nums) {
if (votes == 0) x = num;
votes += num == x ? 1 : -1;
}
for (int num : nums) {
if (num == x) count ++;
}
return count > nums.length / 2 ? x : 0;
}
}
最小的k个数
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
quickSort(arr, 0, arr.length - 1);
return Arrays.copyOf(arr, k);
}
private void quickSort(int[] arr, int l, int r) {
if (l >= r) return ;
int i = l , j = r;
while (i < j) {
while (i < j && arr[j] >= arr[l]) j--;
while (i < j && arr[i] <= arr[l]) i++;
swap(arr, i, j);
}
swap(arr, i, l);
quickSort(arr, l, i - 1);
quickSort(arr, i + 1, r);
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k >= arr.length) return arr;
return quickSort(arr, k, 0, arr.length - 1);
}
private int[] quickSort(int[] arr, int k, int l, int r) {
int i = l, j = r;
while (i < j) {
while (i < j && arr[j] >= arr[l]) j--;
while (i < j && arr[i] <= arr[l]) i++;
swap(arr, i, j);
}
swap(arr, i, l);
if (i > k) return quickSort(arr, k, l, i - 1);
if (i < k) return quickSort(arr, k, i + 1, r);
return Arrays.copyOf(arr, k);
}
private void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
数据流中的中位数
采用大根堆和小根堆
class MedianFinder {
Queue<Integer> min, max;
/** initialize your data structure here. */
public MedianFinder() {
min = new PriorityQueue<>(); //小根堆
max = new PriorityQueue<>((x, y) -> (y - x)); //大根堆
}
public void addNum(int num) {
if (min.size() == max.size()) {
min.add(num);
max.add(min.poll());
} else {
max.add(num);
min.add(max.poll());
}
}
public double findMedian() {
//如果是偶数
if(min.size() == max.size()) {
return (min.peek() + max.peek()) / 2.0;
} else {
return max.peek() * 1.0;
}
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
1~n 整数中 1 出现的次数
class Solution {
public int countDigitOne(int n) {
long bit = 1;
long sum = 0;
while (bit <= n) {
long cur = n / bit % 10;
long low = n % bit;
long high = n /bit / 10;
if (cur > 1) {
sum += (high + 1) * bit;
} else if (cur == 1) {
sum += (high * bit) + (1 + low);
} else if (cur == 0){
sum += high * bit;
}
bit *= 10;
}
return (int)sum;
}
}
数字序列中某一位的数字
class Solution {
public int findNthDigit(int n) {
if (n == 0) return 0;
long bit = 1;
int i = 1;
long count = 9;
while (count < n) {
n = (int)(n - count) ;
bit *= 10;
i++;
count = bit *i * 9;
}
//确定是在这个区间的哪个数
long num = bit + (n - 1)/i;
//确定在Num的那个字符上
int index = (n - 1) % i + 1;
int res =(int) (num / Math.pow(10, i - index)) % 10;
return res;
}
}
把数字翻译成字符串
class Solution {
public int translateNum(int num) {
String s = String.valueOf(num);
int a = 1, b = 1;
for (int i = 2; i <= s.length(); i++) {
String tmp = s.substring(i - 2, i);
int c = tmp.compareTo("10") >= 0 && tmp.compareTo("25") <=0 ? a+ b:a;
b = a;
a = c;
}
return a;
}
}
礼物的最大价值
class Solution {
public int maxValue(int[][] grid) {
int n = grid.length;
int m = grid[0].length;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (i > 0 && j > 0) {
grid[i][j] = Math.max(grid[i][j-1], grid[i - 1][j]) + grid[i][j];
} else if (i > 0) {
grid[i][j] = grid[i - 1][j] + grid[i][j];
} else if (j > 0) {
grid[i][j] = grid[i][j - 1] + grid[i][j];
}
}
}
return grid[n - 1][m - 1];
}
}
最长不含重复字符的子字符串
哈希表
使用双指针的方法 不断更新左指针
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> dic = new HashMap<>();
int i = -1, res = 0;
for (int j = 0; j < s.length(); j++) {
if (dic.containsKey(s.charAt(j))) {
i = Math.max(i, dic.get(s.charAt(j)));
}
dic.put(s.charAt(j), j);//更新hash记录
res = Math.max(res, j - i);
}
return res;
}
}
丑数
class Solution {
public int nthUglyNumber(int n) {
int[] factors = {2, 3, 5};
Set<Long> seen = new HashSet<>();
PriorityQueue<Long> heap = new PriorityQueue<>();
seen.add(1L);
heap.offer(1L);
int ugly = 0;
for (int i = 0; i < n; i++) {
long curr = heap.poll();
ugly = (int) curr;
for (int factor : factors) {
Long next = factor * curr;
if (seen.add(next)) {
heap.offer(next);
}
}
}
return ugly;
}
}
动态规划
巧妙
class Solution {
public int nthUglyNumber(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
int p2 = 1, p3 = 1, p5 = 1;//丑数一定是前面的丑数程2 3 5得来的,所以从第一个数开始
for (int i = 2; i <= n; i++) {
int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
dp[i] = Math.min(num2, Math.min(num3, num5));
if (num2 == dp[i]) p2++;
if (num3 == dp[i]) p3++;
if (num5 == dp[i]) p5++;
}
return dp[n];
}
}
第一个只出现一次的字符
class Solution {
public char firstUniqChar(String s) {
Map<Character, Integer> frequency = new HashMap<>();
for (int i = 0 ; i < s.length(); i++) {
char ch = s.charAt(i);
frequency.put(ch, frequency.getOrDefault(ch, 0) + 1);
}
for (int i = 0 ; i < s.length(); i++) {
if (frequency.get(s.charAt(i)) == 1) return s.charAt(i);
}
return ' ';
}
}
数组中的逆序对
class Solution {
int res;
public int reversePairs(int[] nums) {
res = 0;
mergeSort(nums, 0, nums.length - 1);
return res;
}
public void mergeSort(int[] nums, int l, int r) {
if (l >= r) return ;
int mid = l + r >>1;
mergeSort(nums, l, mid);
mergeSort(nums, mid + 1, r);
int[] tmp = new int[r - l + 1];
int i = l , j = mid +1;
int t = 0;
while (i <= mid && j <= r) {
if (nums[i] <= nums[j]) {
tmp[t++] = nums[i++];
} else {
res += mid - i + 1;
tmp[t++] = nums[j++];
}
}
while (i <= mid) {
tmp[t++] = nums[i++];
}
while (j <= r) {
tmp[t++] = nums[j++];
}
for (int k = 0; k < tmp.length; k++) {
nums[l + k] = tmp[k];
}
}
}
两个链表的第一个公共节点
哈希表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> vis = new HashSet<>();
ListNode tmp = headA;
while (tmp != null) {
vis.add(tmp);
tmp = tmp.next;
}
tmp = headB;
while (tmp!=null) {
if (vis.contains(tmp)) return tmp;
tmp = tmp.next;
}
return null;
}
}
双指针
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headB == null || headA == null) return null;
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pB;
}
}
在排序数组中查找数字 I
二分
class Solution {
public int search(int[] nums, int target) {
if (nums.length == 0) return 0;
int l = 0;
int r = nums.length - 1;
//搜索右边界
while (l < r) {
int mid = l + r + 1 >> 1;
if (nums[mid] <= target) l = mid;
else r = mid - 1;
}
int right = l;
if (r >= 0 &&nums[r] != target) return 0;
l = 0;
r = nums.length - 1;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] >= target) r = mid;
else l = mid + 1;
}
int left = l;
return right - left + 1;
}
}
0~n-1中缺失的数字
class Solution {
public int missingNumber(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i) return i;
}
return nums.length;
}
}
二叉搜索树的第k大节点
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int res, k;
public int kthLargest(TreeNode root, int k) {
this.k = k;
dfs(root);
return res;
}
void dfs(TreeNode root) {
if (root == null) return ;
dfs(root.right);
if (k == 0) return ;
if (--k == 0) res = root.val;
dfs(root.left);
}
}
二叉树的深度
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
} else {
int leftHeight = maxDepth(root.left);
int rightHeight = maxDepth(root.right);
return Math.max(leftHeight, rightHeight) + 1;
}
}
}
平衡二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) {
return true;
} else {
return Math.abs(height(root.left) - height(root.right) ) <= 1 && (isBalanced(root.right) && isBalanced(root.left));
}
}
public int height(TreeNode root) {
if (root == null) return 0;
else {
return Math.max(height(root.left), height(root.right)) + 1;
}
}
}
数组中数字出现的次数
class Solution {
public int[] singleNumbers(int[] nums) {
int x = 0, y = 0, n = 0, m = 1;
for (int num : nums) {
n ^= num;
}
while ((n & m) == 0) {
m <<= 1;
}
for (int num :nums) {
if ((num &m) != 0) x ^= num;
else y ^= num;
}
return new int[] {x, y};
}
}
数组中数字出现的次数 II
class Solution {
public int singleNumber(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() == 1) return entry.getKey();
}
return -1;
}
}
和为s的两个数字
class Solution {
public int[] twoSum(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while (i <j) {
int s= nums[i] +nums[j];
if (s < target) i++;
else if (s > target) j--;
else return new int[] {nums[i], nums[j]};
}
return new int[0];
}
}
和为s的连续正数序列
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> res = new ArrayList<int[]>();
for (int l = 1, r = 2; l < r;) {
int sum = (l + r)*(r - l +1) / 2;
if (sum == target) {
int[] ans = new int[r - l + 1];
for (int i = l; i <= r; i++ ) {
ans[i - l] = i;
}
res.add(ans);
l++;
} else if (sum < target) {
r++;
} else l++;
}
return res.toArray(new int[res.size()][]);
}
}
翻转单词顺序
class Solution {
public String reverseWords(String s) {
// s = s.trim();
// List<String> wordList = Arrays.asList(s.split("\\s+"));
// Collections.reverse(wordList);
// return String.join(" ", wordList);
int left = 0, right = s.length() - 1;
while (left <= right && s.charAt(left) == ' ') {
left ++;
}
while (right >= left && s.charAt(right) == ' ') {
right --;
}
Deque<String> d = new ArrayDeque<String>();
StringBuilder word = new StringBuilder();
while (left <= right) {
char c = s.charAt(left);
if (word.length() != 0 && c == ' ') {
d.offerFirst(word.toString());
word.setLength(0);
} else if (c != ' ') {
word.append(c);
}
left++;
}
d.offerFirst(word.toString());
return String.join(" ", d);
}
}
滑动窗口的最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 0 || k == 0 ) return new int[0];
Deque<Integer> deque = new LinkedList<>();
int[] res = new int[nums.length - k + 1];
for (int i = 0; i < k; i++) {
while (!deque.isEmpty() && deque.peekLast() < nums[i]) {
deque.removeLast();
}
deque.addLast(nums[i]);
}
res[0] = deque.peekFirst();
for (int i = k; i < nums.length; i++) {
if (deque.peekFirst() == nums[i - k]) deque.removeFirst();
while (!deque.isEmpty() && deque.peekLast() < nums[i]) {
deque.removeLast();
}
deque.addLast(nums[i]);
res[i - k + 1] = deque.peekFirst();
}
return res;
}
}
n个骰子的点数
class Solution {
public double[] dicesProbability(int n) {
double[][] dp = new double[n + 1][6 *n + 1];
for (int i = 1; i <= 6; i++) dp[1][i] = (double) 1/6;
for (int i = 2; i <= n; i++){
for (int j = i; j <= 6 * i; j++) {
for (int k = 1; k <= 6; k++ ){
if (j - k < 1) continue;
dp[i][j] += dp[1][k] * dp[i - 1][j - k];
}
}
}
double[] res = new double[5 * n + 1];
int id = n;
for (int i = 0; i < res.length; i++) {
res[i] = dp[n][id++];
}
return res;
}
}
圆圈中最后剩下的数字
class Solution {
public int lastRemaining(int n, int m) {
// return f(n , m);
int f = 0;
for (int i = 2; i != n +1; i++) {
f = (f +m ) %i;
}
return f;
}
// public int f(int n, int m) {
// if (n == 1) return 0;
// return (f(n - 1, m) + m) % n;
// }
}
股票的最大利润
class Solution {
public int maxProfit(int[] prices) {
int cost = Integer.MAX_VALUE, profit = 0;
for (int price :prices) {
cost = Math.min(cost, price);
profit = Math.max(profit, price - cost);
}
return profit;
}
}
求1+2+…+n
class Solution {
public int sumNums(int n) {
return n == 0 ? 0 : n + sumNums(n - 1);
}
}
不用加减乘除做加法
class Solution {
public int add(int a, int b) {
while (b != 0) {
int carry = (a & b) << 1;
a = a ^ b;
b = carry;
}
return a;
}
}
构建乘积数组
class Solution {
public int[] constructArr(int[] a) {
int len = a.length;
if (len == 0) return new int[0];
int[] b = new int[len];
b[0] = 1;
int tmp = 1;
for (int i = 1; i < len; i++) {
b[i] = b[i - 1] * a[i - 1];
}
for (int i = len - 2; i >= 0; i--) {
tmp *= a[i + 1];
b[i] *= tmp;
}
return b;
}
}
二叉搜索树的最近公共祖先
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode ancestor = root;
while (true) {
if (p.val < ancestor.val && q.val < ancestor.val) {
ancestor = ancestor.left;
} else if (p.val > ancestor.val && q.val > ancestor.val) {
ancestor = ancestor.right;
} else break;
}
return ancestor;
}
}
二叉树的最近公共祖先
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right= lowestCommonAncestor(root.right, p, q);
if (left == null) return right;
if (right == null) return left;
return root;
}
}
机器人的运动范围
class Solution {
public int movingCount(int m, int n, int k) {
if (k == 0) return 1;
Queue<int[]> queue = new LinkedList<int[]>();
int[] dx = {0, 1};
int[] dy = {1, 0};
boolean[][] vis = new boolean[m][n];
queue.offer(new int[]{0, 0});
int res = 1;
vis[0][0] = true;
while (queue.size() != 0) {
int[] cell = queue.poll();
int x= cell[0], y = cell[1];
for (int i= 0; i < 2; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if (xx >= 0 && xx < m&& yy >= 0 && yy < n&&vis[xx][yy] == false && (get(xx) + get(yy) <= k)) {
vis[xx][yy] = true;
res ++;
queue.offer(new int[]{xx, yy});
}
}
}
return res;
}
public int get(int x) {
int res = 0;
while (x != 0) {
res += x % 10;
x /= 10;
}
return res;
}
}
把数组排成最小的数
class Solution {
public String minNumber(int[] nums) {
String[] strs = new String[nums.length];
for (int i = 0; i < nums.length; i++) {
strs[i] = String.valueOf(nums[i]);
}
Arrays.sort(strs, (x, y) -> (x + y).compareTo(y + x));
StringBuilder res = new StringBuilder();
for (String s : strs) {
res.append(s);
}
return res.toString();
}
}
队列的最大值
class MaxQueue {
int[] q = new int[20000];
int begin = 0, end = 0;
public MaxQueue() {
}
public int max_value() {
int ans = -1;
for (int i = begin; i != end; ++i) {
ans = Math.max(ans, q[i]);
}
return ans;
}
public void push_back(int value) {
q[end++] = value;
}
public int pop_front() {
if (begin == end) return -1;
return q[begin++];
}
}
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue obj = new MaxQueue();
* int param_1 = obj.max_value();
* obj.push_back(value);
* int param_3 = obj.pop_front();
*/
扑克牌中的顺子
class Solution {
public boolean isStraight(int[] nums) {
Set<Integer> set = new HashSet<>();
int max = 0, min = 14;
for (int num : nums ) {
if (num == 0) continue;
max = Math.max(max, num);
min = Math.min(min, num);
if (set.contains(num)) return false;
set.add(num);
}
return max - min < 5;
}
}
把字符串转换成整数
class Solution {
public:
int strToInt(string str) {
if (str.empty()) return 0;
int index = 0, n = str.size(), sign = 1, res = 0;
while (index < n && str[index] == ' ') index++;
if (index < n && (str[index]=='-' || str[index]=='+')) sign = str[index++] == '+' ? 1 : -1;
while (index < n && isdigit(str[index])) {
int digit = str[index] - '0';
if (res > (INT_MAX - digit) / 10) return sign == 1 ? INT_MAX : INT_MIN;
res = res * 10 + digit;
index++;
}
return res*sign;
}
};