解题视频https://www.bilibili.com/video/BV1cz4y1S7AX?p=1

剑指offer 03.数组中的重复数字

image.png
image.png

  1. class Solution {
  2. public int findRepeatNumber(int[] nums) {
  3. Set<Integer> set = new HashSet<>();
  4. int repeat = -1;
  5. for(int num:nums){
  6. if(!set.add(num)){
  7. repeat = num;
  8. break;
  9. }
  10. }
  11. return repeat;
  12. }
  13. }

剑指offer 04.二维数组中的查找

image.png

  1. class Solution {
  2. public boolean findNumberIn2DArray(int[][] matrix, int target) {
  3. if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
  4. return false;
  5. }
  6. int rows = matrix.length;
  7. int cols = matrix[0].length;
  8. int row = 0;
  9. int col = cols - 1;
  10. while(row < rows && col >=0){
  11. if(matrix[row][col] == target){
  12. return true;
  13. }else if(matrix[row][col] > target){
  14. col--;
  15. }else{
  16. row++;
  17. }
  18. }
  19. return false;
  20. }
  21. }

剑指offer 05.替换空格

image.png

  1. class Solution {
  2. public String replaceSpace(String s) {
  3. int length = s.length();
  4. char[] carry = new char[length * 3];
  5. int size = 0;
  6. for(int i = 0; i< length; i++){
  7. char c = s.charAt(i);
  8. if(c == ' '){
  9. carry[size++] = '%';
  10. carry[size++] = '2';
  11. carry[size++] = '0';
  12. }else{
  13. carry[size++] = c;
  14. }
  15. }
  16. String newStr = new String(carry,0,size);
  17. return newStr;
  18. }
  19. }

剑指offer 06.从尾到头打印链表

image.png
image.png

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public int[] reversePrint(ListNode head) {
  11. if(head == null){
  12. return new int[]{};
  13. }
  14. Stack<Integer> stack = new Stack<>();
  15. ListNode cur = head;
  16. while(cur != null){
  17. stack.push(cur.val);
  18. cur = cur.next;
  19. }
  20. int[] res = new int[stack.size()];
  21. for(int i = 0; i < res.length; i++){
  22. res[i] = stack.pop();
  23. }
  24. return res;
  25. }
  26. }

剑指offer 07.重建二叉树

image.png
image.png

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public TreeNode buildTree(int[] preorder, int[] inorder) {
  12. if(preorder == null || preorder.length == 0){
  13. return null;
  14. }
  15. HashMap<Integer,Integer> hashmap = new HashMap<>();
  16. for(int i = 0; i < inorder.length; i++){
  17. hashmap.put(inorder[i],i);
  18. }
  19. return dfs(preorder,0,preorder.length - 1,0,hashmap);
  20. }
  21. public TreeNode dfs(int[] preorder,int pl,int pr,int il,HashMap<Integer,Integer> hashmap){
  22. if(pl > pr){
  23. return null;
  24. }
  25. TreeNode curRoot = new TreeNode(preorder[pl]);
  26. int k = hashmap.get(curRoot.val);
  27. curRoot.left = dfs(preorder,pl+1,pl+(k-il),il,hashmap);
  28. curRoot.right = dfs(preorder,pl+(k-il)+1,pr,k+1,hashmap);
  29. return curRoot;
  30. }
  31. }
  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public TreeNode buildTree(int[] preorder, int[] inorder) {
  12. if(preorder == null || preorder.length == 0){
  13. return null;
  14. }
  15. Map<Integer, Integer> indexMap = new HashMap<>();
  16. int length = preorder.length;
  17. for(int i = 0; i < length; i++){
  18. indexMap.put(inorder[i],i);
  19. }
  20. TreeNode root = buildTree(preorder,0,length -1,inorder,0,length-1,indexMap);
  21. return root;
  22. }
  23. public TreeNode buildTree(int[] preorder, int preorderStart,int preorderEnd,int[] inorder,int inorderStart,int inorderEnd,Map<Integer,Integer> indexMap){
  24. if(preorderStart > preorderEnd){
  25. return null;
  26. }
  27. int rootVal = preorder[preorderStart];
  28. TreeNode root = new TreeNode(rootVal);
  29. if(preorderStart == preorderEnd){
  30. return root;
  31. }else{
  32. int rootIndex = indexMap.get(rootVal);
  33. int leftNodes = rootIndex - inorderStart,rightNodes = inorderEnd - rootIndex;
  34. TreeNode leftSubtree = buildTree(preorder,preorderStart+1,preorderStart+leftNodes,inorder,inorderStart,rootIndex -1,indexMap);
  35. TreeNode rightSubtree = buildTree(preorder,preorderEnd - rightNodes + 1,preorderEnd,inorder,rootIndex + 1,inorderEnd,indexMap);
  36. root.left = leftSubtree;
  37. root.right = rightSubtree;
  38. return root;
  39. }
  40. }
  41. }

剑指offer 09.用两个栈实现队列

image.png
image.png

  1. class CQueue {
  2. private Stack<Integer> stackin;
  3. private Stack<Integer> stackout;
  4. public CQueue() {
  5. stackin = new Stack<>();
  6. stackout = new Stack<>();
  7. }
  8. public void appendTail(int value) {
  9. stackin.push(value);
  10. }
  11. public int deleteHead() {
  12. if(stackout.isEmpty()){
  13. while(!stackin.isEmpty()){
  14. stackout.push(stackin.pop());
  15. }
  16. }
  17. if(!stackout.isEmpty()){
  18. return stackout.pop();
  19. }else{
  20. return -1;
  21. }
  22. }
  23. }
  24. /**
  25. * Your CQueue object will be instantiated and called as such:
  26. * CQueue obj = new CQueue();
  27. * obj.appendTail(value);
  28. * int param_2 = obj.deleteHead();
  29. */
  1. class CQueue {
  2. private Deque<Integer> stackin;
  3. private Deque<Integer> stackout;
  4. public CQueue() {
  5. stackin = new LinkedList<>();
  6. stackout = new LinkedList<>();
  7. }
  8. public void appendTail(int value) {
  9. stackin.push(value);
  10. }
  11. public int deleteHead() {
  12. if(stackout.isEmpty()){
  13. while(!stackin.isEmpty()){
  14. stackout.push(stackin.pop());
  15. }
  16. }
  17. if(!stackout.isEmpty()){
  18. return stackout.pop();
  19. }else{
  20. return -1;
  21. }
  22. }
  23. }
  24. /**
  25. * Your CQueue object will be instantiated and called as such:
  26. * CQueue obj = new CQueue();
  27. * obj.appendTail(value);
  28. * int param_2 = obj.deleteHead();
  29. */

剑指offer 10-1.斐波那契数列

image.pngimage.png

  1. class Solution {
  2. public int fib(int n) {
  3. if(n == 0){
  4. return 0;
  5. }
  6. int a = 0;
  7. int b = 1;
  8. int sum = 0;
  9. for(int i= 0; i < n; i++){
  10. sum = (a+b)%1000000007;
  11. a = b;
  12. b = sum;
  13. }
  14. return a;
  15. }
  16. }

剑指offer 10-2.青蛙跳台阶问题

image.png

剑指offer 11.旋转数组的最小数字

image.png

  1. class Solution {
  2. public int minArray(int[] numbers) {
  3. int low = 0;
  4. int hight = numbers.length - 1;
  5. while(low < hight){
  6. int pivot = low + (hight - low)/2;
  7. if(numbers[pivot] < numbers[hight]){
  8. hight = pivot;
  9. }else if(numbers[pivot] > numbers[hight]){
  10. low = pivot + 1;
  11. }else if(numbers[pivot] == numbers[hight]){
  12. hight--;
  13. }
  14. }
  15. return numbers[low];
  16. }
  17. }

剑指offer 12.矩阵中的路径

  1. class Solution {
  2. public boolean exist(char[][] board, String word) {
  3. if(board == null || board.length == 0) return false;
  4. int rows = board.length;
  5. int cols = board[0].length;
  6. boolean[][] isVisited = new boolean[rows][cols];//标记数组
  7. //路径可以从矩阵中任意一格开始,所以分别以矩阵中的每一个字符作为起点寻找
  8. for(int i = 0; i < rows;i++){
  9. for(int j = 0; j < cols; j++){
  10. if(dfs(board,word,0,i,j,isVisited)){
  11. return true;
  12. }
  13. }
  14. }
  15. return false;
  16. }
  17. //参数说明,n表示当前访问到第几个字符了,(x,y)表示当前要访问的字符在board中的坐标
  18. private boolean dfs(char[][] board,String word,int n,int x,int y,boolean[][] isVisited){
  19. //当前位置和我们需要的字符word.charAt(n)不同,该路径行不通
  20. if(board[x][y] != word.charAt(n)) return false;
  21. //我们要查找的最后一个字符都通过了上面那条if语句,该单词路径存在
  22. if(n == word.length() - 1) return true;
  23. isVisited[x][y] = true;//标记board[x][y]已经被访问过了
  24. //定义左右上下四个方向(偏移量技巧)
  25. int[] dx = {-1,1,0,0};
  26. int[] dy = {0,0,-1,1};
  27. for(int i = 0; i < 4;i++){//分别尝试往左右上下四个方向走
  28. //改变方向,注意这里不是用x = x+dx[i],而是用a和b接收,以保证下轮循环时x,y是原来的值
  29. int a = x + dx[i];
  30. int b = y + dy[i];
  31. //保证a,b不越界,且board[a][b]还未被访问过
  32. if(a >= 0 && a < board.length && b >= 0 && b < board[0].length && !isVisited[a][b]){
  33. if(dfs(board,word,n+1,a,b,isVisited)){
  34. return true;
  35. }
  36. }
  37. }
  38. isVisited[x][y] = false; //状态回退
  39. return false;
  40. }
  41. }

image.png

  1. class Solution {
  2. public boolean exist(char[][] board, String word) {
  3. char[] words = word.toCharArray();
  4. for(int i = 0; i < board.length; i++){
  5. for(int j = 0; j < board[0].length; j++){
  6. if(dfs(board, words, i, j, 0)){
  7. return true;
  8. }
  9. }
  10. }
  11. return false;
  12. }
  13. public boolean dfs(char[][] board, char[] word, int i, int j, int k){
  14. if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]){
  15. return false;
  16. }
  17. if(k == word.length - 1){
  18. return true;
  19. }
  20. board[i][j] = '\0';
  21. boolean res = dfs(board, word, i+1, j, k+1) || dfs(board, word, i - 1, j, k+1) ||
  22. dfs(board, word, i, j + 1, k+1) || dfs(board, word, i ,j -1, k+1);
  23. board[i][j] = word[k];
  24. return res;
  25. }
  26. }

剑指offer 13.机器人的运动范围

递归参数的设置,与变量的作用域有关,局部 变量不可以调用,必须设置为全局变量才可以

image.png
image.png
image.png
image.png
image.png
image.png

  1. class Solution {
  2. private int count = 0;
  3. public int movingCount(int m, int n, int k) {
  4. if(m < 0||n < 0){
  5. return -1;
  6. }
  7. boolean[][] isVisited = new boolean[m][n];
  8. dfs(m,n,k,isVisited,0,0);
  9. return count;
  10. }
  11. private void dfs(int m,int n,int k,boolean[][] isVisited,int x,int y){
  12. //坐标越界或者已经访问过,直接返回退出本次调用栈
  13. if(x < 0 || x >=m||y < 0 ||y >= n|| isVisited[x][y]){
  14. return;
  15. }
  16. isVisited[x][y] = true;//标记该坐标访问过了;
  17. //当确定机器人可以进入该坐标之后,才需要从这坐标向四个方向扩散
  18. if(getSum(x,y) <= k){
  19. count++;
  20. int[] dx = {-1,1,0,0};
  21. int[] dy = {0,0,-1,1};
  22. for(int i = 0; i < 4; i++){
  23. int a = x + dx[i];
  24. int b = y + dy[i];
  25. dfs(m,n,k,isVisited,a,b);
  26. }
  27. }else{
  28. return; //机器人无法到达
  29. }
  30. }
  31. private int getSum(int x,int y){
  32. int res = 0;
  33. while(x > 0){
  34. res += x % 10;
  35. x /=10;
  36. }
  37. while(y > 0){
  38. res += y % 10;
  39. y /= 10;
  40. }
  41. return res;
  42. }
  43. }

剑指offer 14-|.减绳子

image.png
image.png
image.png
image.png

  1. class Solution {
  2. public int cuttingRope(int n) {
  3. if(n <= 3){
  4. return n-1;
  5. }
  6. int a = n/3;
  7. int b = n%3;
  8. if(b == 1){
  9. return (int)Math.pow(3,(a-1))*4;
  10. }
  11. if(b == 0){
  12. return (int)Math.pow(3,a);
  13. }
  14. return (int)Math.pow(3,a)*2;
  15. }
  16. }

剑指offer 14-||.减绳子||

image.png
image.png

  1. class Solution {
  2. public int cuttingRope(int n) {
  3. if(n<=3) return n-1;
  4. int a=n/3;
  5. int b=n%3;
  6. //循环a-1次:res=pow(3,a-1)
  7. long res=1;
  8. int mod=1000000007;
  9. for(int i=0;i<a-1;i++){
  10. res=res*3;
  11. res=res%mod;
  12. }
  13. if(b==0)//乘3 pow(3,a)
  14. return (int)(res*3%mod);
  15. if(b==1)//乘4 pow(3,a-1)*4
  16. return (int)(res*4%mod);
  17. else//乘3 乘2 pow(3,a)*2
  18. return (int)((res*3%mod)*2%mod);
  19. }
  20. }

剑指offer 15.二进制中1的个数

image.png

  1. public class Solution {
  2. // you need to treat n as an unsigned value
  3. public int hammingWeight(int n) {
  4. int result = 0;
  5. while(n != 0){
  6. result = result + (n & 1);
  7. n = n >>> 1;
  8. }
  9. return result;
  10. }
  11. }

剑指offer 16.数值的整数次方

image.png
image.png
image.png

  1. class Solution {
  2. public double myPow(double x, int n) {
  3. //快速幂
  4. //n可以用二进制表示
  5. //9=1001=1*1 + 0*2 + 0*4 + 1*8
  6. //x^9 = x^(1*1) x^(0*2) x^(0*4) x^(1*8)
  7. if(x == 0){
  8. return 0;
  9. }
  10. //int范围[−2147483648,2147483647],当n = -2147483648,时执行 n = -n会越界,使用long类型
  11. long b = n;
  12. double res = 1.0;
  13. if(b < 0){
  14. b = -b;
  15. x = 1/x;
  16. }
  17. while(b > 0){
  18. if((b & 1) == 1){
  19. res = res * x; //累乘 //指数
  20. }
  21. x = x * x; //相当于x^2 //底数 每次都要平方
  22. b = b >>> 1; //右移一位
  23. }
  24. return res;
  25. }
  26. }

剑指offer 17.打印从1到最大的n位数

image.png

  1. class Solution {
  2. public int[] printNumbers(int n) {
  3. if(n <= 0){
  4. return new int[0];
  5. }
  6. int max = (int)Math.pow(10, n);
  7. int[] arr = new int[max - 1];
  8. for(int i = 0; i < max-1; i++){
  9. arr[i] = i + 1;
  10. }
  11. return arr;
  12. }
  13. }

剑指offer 18.删除链表的节点

image.png

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public ListNode deleteNode(ListNode head, int val) {
  11. ListNode domp = new ListNode(-1);
  12. domp.next = head;
  13. ListNode tem = domp;
  14. while(tem.next != null){
  15. if(tem.next.val == val){
  16. tem.next = tem.next.next;
  17. break;
  18. }
  19. tem = tem.next;
  20. }
  21. return domp.next;
  22. }
  23. }

image.png

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public ListNode deleteNode(ListNode head, int val) {
  11. if(head == null){
  12. return head;
  13. }
  14. if(head.val == val){
  15. return head.next;
  16. }
  17. ListNode pre = head;
  18. ListNode last = head.next;
  19. while(last.next != null && last.val != val){
  20. pre = last;
  21. last = last.next;
  22. }
  23. pre.next = (last == null) ? null:last.next;
  24. return head;
  25. }
  26. }

剑指offer 19.正则表达式匹配

image.png

  1. class Solution {
  2. static boolean[][] dp;
  3. static int n,m;
  4. public static boolean isMatch(String s, String p){
  5. char[] ss = s.toCharArray();
  6. char[] ps = p.toCharArray();
  7. dp = new boolean[ss.length + 1][ps.length + 1];
  8. n = ss.length;
  9. m = ps.length;
  10. dp[n][m] = true;
  11. return dp(0,0,ss,ps);
  12. }
  13. private static boolean dp(int i, int j, char[] ss, char[] ps){
  14. if (dp[i][j]){
  15. return dp[i][j];
  16. }
  17. // 模式串匹配完成,判断是否匹配完字符串
  18. if (j == m){
  19. return dp[i][j] = i == n;
  20. }
  21. // 出现两个串字符相同或者模式串为'.'时则为true
  22. boolean firstMatch = i < n && (ss[i] == ps[j] || ps[j] == '.');
  23. boolean ans;
  24. if (j + 1 < m && ps[j + 1] == '*'){
  25. // j + 2意味着 *号和之前的一个元素没有被匹配到则跳过
  26. ans = dp(i,j + 2, ss, ps) || firstMatch && dp(i + 1, j, ss, ps);
  27. }else {
  28. ans = firstMatch && dp(i + 1, j + 1, ss, ps);
  29. }
  30. return dp[i][j] = ans;
  31. }
  32. }
  1. class Solution {
  2. public boolean isMatch(String s, String p) {
  3. int m = s.length();
  4. int n = p.length();
  5. boolean[][] f = new boolean[m + 1][n + 1];
  6. f[0][0] = true;
  7. for(int i = 0; i <= m; ++i){
  8. for(int j = 1; j <= n; ++j){
  9. if(p.charAt(j - 1) == '*'){
  10. f[i][j] = f[i][j - 2];
  11. if(matches(s, p ,i , j - 1)){
  12. f[i][j] = f[i][j] || f[i - 1][j];
  13. }
  14. }else{
  15. if(matches(s, p, i, j)){
  16. f[i][j] = f[i - 1][j - 1];
  17. }
  18. }
  19. }
  20. }
  21. return f[m][n];
  22. }
  23. public boolean matches(String s, String p, int i, int j){
  24. if(i == 0){
  25. return false;
  26. }
  27. if(p.charAt(j - 1) == '.'){
  28. return true;
  29. }
  30. return s.charAt(i - 1) == p.charAt(j - 1);
  31. }
  32. }

剑指offer 20.表示数值的字符串

  1. class Solution {
  2. public boolean isNumber(String s) {
  3. int n = s.length();
  4. int index = 0;
  5. boolean hasNum = false, hasE = false;
  6. boolean hasSign = false, hasDot = false;
  7. while(index < n && s.charAt(index) == ' ')
  8. index++;
  9. while(index < n){
  10. while(index < n && s.charAt(index) >= '0' && s.charAt(index) <= '9'){
  11. index++;
  12. hasNum = true;
  13. }
  14. if(index == n){
  15. break;
  16. }
  17. char c = s.charAt(index);
  18. if(c == 'e' || c == 'E'){
  19. if(hasE || !hasNum){
  20. return false;
  21. }
  22. hasE = true;
  23. hasNum = false; hasSign = false; hasDot = false;
  24. }else if(c == '+' || c == '-'){
  25. if(hasSign || hasNum || hasDot){
  26. return false;
  27. }
  28. hasSign = true;
  29. }else if(c == '.'){
  30. if(hasDot || hasE){
  31. return false;
  32. }
  33. hasDot = true;
  34. }else if(c == ' '){
  35. break;
  36. }else{
  37. return false;
  38. }
  39. index++;
  40. }
  41. while(index < n && s.charAt(index) == ' ')
  42. index++;
  43. return hasNum && index == n;
  44. }
  45. }

剑指offer 21.调整数组顺序使奇数位于偶数前

image.png

  1. class Solution {
  2. public int[] exchange(int[] nums) {
  3. if(nums == null || nums.length == 0) return nums;
  4. int[] res = new int[nums.length];
  5. int left = 0;
  6. int right = nums.length - 1;
  7. for(int i = 0; i < nums.length; i++){
  8. if(nums[i] % 2 != 0){
  9. res[left++] = nums[i]; //奇数从前往后放
  10. }else{
  11. res[right--] = nums[i]; //偶数从后往前放
  12. }
  13. }
  14. return res;
  15. }
  16. }

image.png

  1. class Solution {
  2. public int[] exchange(int[] nums) {
  3. if(nums.length == 0){
  4. return nums;
  5. }
  6. int length = nums.length;
  7. int length1 = length - 1;
  8. int length2 = 0;
  9. int[] arr = new int[length];
  10. for(int i = 0; i < length; i++){
  11. if(nums[i] % 2 != 0){
  12. arr[length2] = nums[i];
  13. length2++;
  14. }else{
  15. arr[length1] = nums[i];
  16. length1--;
  17. }
  18. }
  19. return arr;
  20. }
  21. }

剑指offer 22.链表中倒数第k个节点

image.png

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public ListNode getKthFromEnd(ListNode head, int k) {
  11. ListNode fir = head;
  12. ListNode sec = head;
  13. for(int i = 0; i < k; i++){
  14. fir = fir.next;
  15. }
  16. while(fir != null){
  17. fir = fir.next;
  18. sec = sec.next;
  19. }
  20. return sec;
  21. }
  22. }

剑指offer 24.反转链表

image.png

  1. /*** Definition for singly-linked list.
  2. * public class ListNode {
  3. * int val;
  4. * ListNode next;
  5. * ListNode(int x) { val = x; }
  6. * }
  7. */
  8. class Solution {
  9. public ListNode reverseList(ListNode head) {
  10. ListNode pre = null;
  11. ListNode cur = head;
  12. while(cur != null){
  13. ListNode next = cur.next;
  14. cur.next = pre;
  15. pre = cur;
  16. cur = next;
  17. }
  18. return pre;
  19. }
  20. }

剑指offer 25.合并两个排序的链表

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  11. if(l1 == null) return l2;
  12. if(l2 == null) return l1;
  13. ListNode p1 = l1; //用于遍历l1
  14. ListNode p2 = l2; //用于遍历l2
  15. ListNode dummy = new ListNode(0); //新建链表虚拟头节点
  16. ListNode cur = dummy; //辅助构建新链表
  17. //两个链表都未遍历结束时,比较当前节点的大小,拼接到新链表之后
  18. while(p1 != null && p2 != null){
  19. if(p1.val < p2.val){
  20. cur.next = p1;
  21. p1 = p1.next;
  22. cur = cur.next;
  23. }else{
  24. cur.next = p2;
  25. p2 = p2.next;
  26. cur = cur.next;
  27. }
  28. }
  29. //退出while循环后,说明肯定有一个链表遍历结束
  30. if(p1 == null){
  31. cur.next = p2;
  32. }
  33. if(p2 == null){
  34. cur.next = p1;
  35. }
  36. return dummy.next;
  37. }
  38. }

image.png

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  11. ListNode pom = new ListNode(0);
  12. ListNode cur = pom;
  13. while(l1 != null && l2 != null){
  14. if(l1.val < l2.val){
  15. cur.next = l1;
  16. l1 = l1.next;
  17. }else{
  18. cur.next = l2;
  19. l2 = l2.next;
  20. }
  21. cur = cur.next;
  22. }
  23. cur.next = l1 != null ? l1:l2;
  24. return pom.next;
  25. }
  26. }

剑指offer 26.树的子结构

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public boolean isSubStructure(TreeNode A, TreeNode B) {
  12. if(A == null || B == null) return false;
  13. //直接判断A是否是B作为根节点的开始的一部分,不是再递归A,让A的左右节点分别作为新树的根节点
  14. if(isPart(A,B)) return true;
  15. return isSubStructure(A.left,B) || isSubStructure(A.right,B);
  16. }
  17. public boolean isPart(TreeNode A,TreeNode B){
  18. //A和B根节点相同,再递归的判断他们各自的左右节点的值是否相同,递归的终止条件是:
  19. //到达了树A或树B的叶子节点,或者两个的值不相等
  20. if(B == null) return true;
  21. //通过上面的if判断,说明B当前节点不是空,
  22. //如果此时A空了,或者A和B当前节点的值不同,则B不是A的子结构
  23. if(A == null || A.val != B.val) return false;
  24. return isPart(A.left, B.left) && isPart(A.right, B.right);
  25. }
  26. }

image.png

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public boolean isSubStructure(TreeNode A, TreeNode B) {
  12. return (A != null && B != null) && (res(A,B) || isSubStructure(A.left, B) || isSubStructure(A.right,B));
  13. }
  14. private boolean res(TreeNode A, TreeNode B){
  15. if(B == null){
  16. return true;
  17. }
  18. if(A == null || A.val != B.val){
  19. return false;
  20. }
  21. return res(A.left, B.left) && res(A.right, B.right);
  22. }
  23. }

剑指offer 27.二叉树的镜像

image.png

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public TreeNode mirrorTree(TreeNode root) {
  12. //前序遍历二叉树,将非叶子节点的左右节点互换一下即可
  13. if(root == null) return null;
  14. swap(root);
  15. mirrorTree(root.left);
  16. mirrorTree(root.right);
  17. return root;
  18. }
  19. //交换根节点的左右子节点,root的左右孩子是null也可以用swap函数,只要root不是null即可
  20. //毕竟root是null,root.legt root.right就空指针异常了
  21. private void swap(TreeNode root){
  22. TreeNode temp = root.left;
  23. root.left = root.right;
  24. root.right = temp;
  25. }
  26. }

剑指offer 28.对称的二叉树

image.png

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. //递归判断两个子树是否互为镜像。
  11. //两个子树互为镜像当且仅当:
  12. //1. 两个子树的根节点值相等;
  13. //2. 第一棵子树的左子树和第二棵子树的右子树互为镜像,且第一棵子树 的右子树和第二棵子树的左子树互为镜像。
  14. class Solution {
  15. public boolean isSymmetric(TreeNode root) {
  16. if(root == null) return true;
  17. return dfs(root,root);
  18. }
  19. public boolean dfs(TreeNode p, TreeNode q){
  20. if(p == null && q == null) return true; //两树空视为想等
  21. if(p == null || q == null) return false; //结合上一个if,代表一个为空,另一个不为空,不可能相等
  22. if(p.val != q.val) return false; //镜像的值不同
  23. return dfs(p.left, q.right) && dfs(p.right, q.left);
  24. }
  25. }

剑指offer 29.顺序打印矩阵

image.png

  1. class Solution {
  2. public int[] spiralOrder(int[][] matrix) {
  3. if(matrix.length == 0) return new int[0];
  4. int l = 0; //左边界
  5. int r = matrix[0].length-1; //右边界
  6. int t = 0; //上边界
  7. int b = matrix.length - 1; //下边界
  8. int x = 0;
  9. int[] res = new int[(r + 1) * (b + 1)];
  10. while(true){
  11. for(int i = l;i <= r;i++) res[x++] = matrix[t][i];// left to right.
  12. if(++t > b) break;
  13. for(int i = t;i <= b;i++) res[x++] = matrix[i][r];// top to bottom.
  14. if(l > --r) break;
  15. for(int i = r;i >= l;i--) res[x++] = matrix[b][i];// right to left.
  16. if(t > --b) break;
  17. for(int i = b;i >= t;i--) res[x++] = matrix[i][l];// bottom to top.
  18. if(++l > r) break;
  19. }
  20. return res;
  21. }
  22. }

剑指offer 30.包含min函数的栈

class MinStack {
    Stack<Integer> stack;//实际数据栈
    Stack<Integer> minStack;//辅助栈,栈顶一直存储当前最小元素,数据个数和实际数据栈中个数一致

    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();

    }

    public void push(int x) {
        stack.push(x);
        //辅助栈为空或者当前入栈元素小于之前的最小值,说明当前元素就是最小值
        if(minStack.isEmpty() || x < minStack.peek()){
            minStack.push(x);
        }else{//辅助栈顶元素仍然是最小的,让他再次入栈
            int temp = minStack.peek();
            minStack.push(temp);    
        }
    }

    public void pop() {
        stack.pop();
        //数据栈弹出了一个元素,辅助栈相应弹出一个元素
        minStack.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int min() {
        return minStack.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();
 */

image.png
image.png

剑指offer 31.栈的压入,弹出序列

image.png

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        if(pushed == null){
            return false;
        }
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(int num : pushed){
            stack.push(num);
            while(!stack.isEmpty() && popped[i] == stack.peek()){
                stack.pop();
                i++;
            }
        }
        return stack.isEmpty();

    }
}

剑指offer 32-1.从上到下打印二叉树

image.png

/**
 * 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<>();
        ArrayList<Integer> arr = new ArrayList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            arr.add(node.val);
            if(node.left != null){
                queue.add(node.left);
            }
            if(node.right != null){
                queue.add(node.right);
            }
        }
        int[] res = new int[arr.size()];
        for(int i = 0; i < res.length; i++){
            res[i] = arr.get(i);
        }
        return res;
    }
}

剑指offer 32-2.从上到下打印二叉树

image.png

/**
 * 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<>();
        ArrayList<Integer> arr = new ArrayList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            arr.add(node.val);
            if(node.left != null){
                queue.add(node.left);
            }
            if(node.right != null){
                queue.add(node.right);
            }
        }
        int[] res = new int[arr.size()];
        for(int i = 0; i < res.length; i++){
            res[i] = arr.get(i);
        }
        return res;
    }
}

剑指offer 32-3.从上到下打印二叉树

image.png

/**
 * 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) {
        List<List<Integer>> res = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        if(root != null){
            queue.add(root);
        }
        while(!queue.isEmpty()){
            int size = queue.size();
            LinkedList<Integer> list = new LinkedList<>();
            for(int i = 0; i < size; i++){
                TreeNode node = queue.poll();
                if(res.size() % 2 == 0){
                    list.addLast(node.val);
                }else{
                    list.addFirst(node.val);
                }
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            res.add(list);
        }
        return res;
    }
}

剑指offer 33.二叉树的后序遍历序列

image.png

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return res(postorder, 0 , postorder.length - 1);

    }

    private boolean res(int[] postorder, int i, int j){
        if(i >= j){
            return true;
        }
        int p = i;
        while(postorder[p] < postorder[j]) p++;
        int m = p;
        while(postorder[p] > postorder[j]) p++;
        return p==j&&res(postorder, i , m-1)&&res(postorder, m ,j-1);
    }
}

剑指offer 34.二叉树中和为某一值的路径

image.png

/**
 * 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 {
    LinkedList<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> path = new LinkedList<>();

    public List<List<Integer>> pathSum(TreeNode root, int target) {
        res(root, target);
        return res;
    }

    public void res(TreeNode root, int target){
        if(root == null){
            return;
        }
        path.add(root.val);
        target = target - root.val;
        if(target == 0 && root.left== null && root.right==null){
            res.add(new LinkedList(path));
        }
        res(root.left, target);
        res(root.right, target);
        path.removeLast();
    }

}

剑指offer 35.复杂链表的复制

image.png
image.png

/*
// 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 copy = new Node(cur.val);
            copy.next = cur.next;
            cur.next = copy;
            cur = cur.next.next;;
        }

        //第二步:复制random指针
        cur = head;
        while(cur != null ){
            if(cur.random != null){
                 cur.next.random = cur.random.next;
            }
            cur = cur.next.next;
        }

        //第三步:分开两个链表,并将原链表还原。
        Node dummy = new Node(-1);//复制链表的虚拟头节点
        Node help = dummy;//辅助建立复制的链表
        cur = head;
        while(cur != null){
            help.next = cur.next;
            help = help.next;
            cur.next = cur.next.next;
            cur = cur.next;
        }

        return dummy.next;
    }
}

剑指offer 36.二叉搜索树与双向链表

image.png
image.png

/*
// 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 {
    Node head, pre;
    public Node treeToDoublyList(Node root) {
        if(root==null) return null;
        dfs(root);
        pre.right = head;
        head.left =pre;//进行头节点和尾节点的相互指向,这两句的顺序也是可以颠倒的
        return head;

    }

    public void dfs(Node cur){
        if(cur==null) return;
        dfs(cur.left);
        //pre用于记录双向链表中位于cur左侧的节点,即上一次迭代中的cur,
        //当pre==null时,cur左侧没有节点,即此时cur为双向链表中的头节点
        if(pre==null) head = cur;
        //反之,pre!=null时,cur左侧存在节点pre,需要进行pre.right=cur的操作。
        else pre.right = cur;
        cur.left = pre;//pre是否为null对这句没有影响,且这句放在上面两句if else之前也是可以的。
        pre = cur;//pre指向当前的cur
        dfs(cur.right);//全部迭代完成后,pre指向双向链表中的尾节点
    }
}

剑指offer 37.序列化二叉树

image.png
image.png

/**
 * 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 t = q.poll();
            if(t != null){
                res.append(t.val + ",");
                q.add(t.left);
                q.add(t.right);
            }else{
                res.append("null,");
            }
        }
        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));

剑指offer 38.字符串的排列

image.png

class Solution {
    Set<String> res = new HashSet<>();
    public String[] permutation(String s) {
        if(s == null) return new String[]{};
        boolean[] visisted = new boolean[s.length()];
        dfs(s, "", visisted);
        return res.toArray(new String[res.size()]);

    }

    private void dfs(String s, String ch, boolean[] visisted){
        if(s.length() == ch.length()){
            res.add(ch);  //abc
            return;
        }
        for(int i = 0; i < s.length(); i++){
            char temp = s.charAt(i);
            if(visisted[i]) continue;
            visisted[i] = true;
            dfs(s, ch + String.valueOf(temp), visisted);
            visisted[i] = false;
        }        
    }
}

剑指offer 39.数组中出现次数超过一半的数字

image.png

class Solution {
    public int majorityElement(int[] nums) {
        int val = -1;
        int cnt = 0;
        for(int num: nums){
            if(num == val){
                cnt++;
            }else{
                if(cnt >= 1){
                    cnt--;
                }else{
                    val = num;
                    cnt = 1;
                }
            }
        }
        return val;
    }
}

image.png

剑指offer 40.最小的k个数

image.png

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] res = new int[k];
        //PriorityQueue是Queue的一个实现类
        //默认是小顶堆,建立大顶堆则需要构造时传自定义的Comparator参数
        Queue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return o2 - o1;//从大到小排
            }
        });

        //大顶堆中保留最小的k个数
        for(int i = 0;i < arr.length;i++){
            queue.add(arr[i]);
            if(queue.size() > k) queue.poll();
        }

        for(int i = 0;i < k;i++){
            res[i] = queue.poll();
        }

        return res;
    }
}

image.png

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k == 0 || arr.length == 0){
            return new int[0];
        }
        return qsk(arr, 0, arr.length - 1, k - 1);

    }

    private int[] qsk(int[] nums, int l, int r, int k){
        int j = quicksort(nums, l , r);
        if(j == k){
            return Arrays.copyOf(nums, j+1);
        }
        return j > k ? qsk(nums, l , j - 1, k): qsk(nums, j+1, r, k);
    }

    private int quicksort(int[] nums, int l ,int r){
        int v = nums[l];
        int i = l, j = r + 1;
        while(true){
            while(++i <= r && nums[i] < v);
            while(--j >=l && nums[j] > v);
            if(i >= j){
                break;
            }
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
        nums[l] = nums[j];
        nums[j] = v;
        return j;  //保证Nums[j] 左边是最小的j个数字
    }
}

剑指offer 41.数据流中的中位数

image.png
image.png

class MedianFinder {
    Queue<Integer> minQueue;
    Queue<Integer> maxQueue;

    /** initialize your data structure here. */
    public MedianFinder() {
        minQueue = new PriorityQueue<>();
        maxQueue = new PriorityQueue<>(new Comparator<Integer>(){
                @Override
                public int compare(Integer o1,Integer o2){
                    return o2 - o1;
                }
        });
    }

    public void addNum(int num) {
        maxQueue.add(num);
        if(!minQueue.isEmpty() && maxQueue.peek() > minQueue.peek()){
            int temp1 = maxQueue.poll();
            int temp2 = minQueue.poll();
            maxQueue.add(temp2);
            minQueue.add(temp1);
        }
        if(maxQueue.size() > minQueue.size() + 1){
            int temp = maxQueue.poll();
            minQueue.add(temp);
        }
    }

    public double findMedian() {
        int count = minQueue.size() + maxQueue.size();//数据流中当前共有多少数
        if((count & 1) != 0){//奇数
            return maxQueue.peek();
        }else{//偶数
            //注意需要返回的是double类型,故除2.0,写成2的话是整数除法,返回int型
            return (maxQueue.peek() + minQueue.peek()) / 2.0;
        }
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

image.png
image.png
image.png

class MedianFinder {
    Queue<Integer> A, B;

    /** initialize your data structure here. */
    public MedianFinder() {
        A = new PriorityQueue<>();//小根堆 存大的一半数字
        B = new PriorityQueue<>((x,y) -> (y - x));//大根堆 存小的一半数字
    }

    public void addNum(int num) {
         if(A.size() != B.size()){
            A.add(num);//无脑放进小根堆
            B.add(A.poll());//把小根堆中较小数字 放进大根堆
        }else{
            //堆顶比较 确保大小根堆的 一半的特性
            B.add(num);//大数字 在堆顶
            A.add(B.poll());//通过添加堆顶数字 确保 特性
        }
    }

    public double findMedian() {
        return A.size() == B.size() ? (A.peek() + B.peek())/2.0 : A.peek();
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

剑指offer 42.连续子数组的最大和

image.png

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];

        for(int i = 1; i < nums.length; i++){
            nums[i] += Math.max(nums[i - 1], 0);
            res = Math.max(res, nums[i]);
        }
        return res;
    }
}

image.png

class Solution {
    public int maxSubArray(int[] nums) {
        // int res = nums[0];

        // for(int i = 1; i < nums.length; i++){
        //     nums[i] = nums[i] + Math.max(nums[i - 1], 0);
        //     res = Math.max(res, nums[i]);
        // }
        // return res;

        int length = nums.length;
        int[] dp = new int[length];
        dp[0] = nums[0];
        int res = nums[0];
        for(int i = 1; i < length; i++){
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

剑指offer 43.1~n整数中1出现的次数

image.png
image.png

class Solution {
    public int countDigitOne(int n) {
        int x = 1, res = 0;
        int high = n / 10, cur = n % 10, low = 0;
        while(cur != 0 || high != 0){
            if(cur == 0){
                res += high * x;
            }else if(cur == 1){
                res += high * x + low + 1;
            }else{
                res += (high + 1) * x;
            }

            low += cur * x;
            cur = high % 10;
            high /= 10;
            x *= 10;
        }
        return res;
    }
}

image.png

剑指 Offer 44. 数字序列中某一位的数字

image.png

class Solution {
    public int findNthDigit(int n) {
        int digit = 1;
        long start = 1;
        long count = 9;
        while(n > count){
            n -= count;
            digit += 1;
            start *= 10;
            count = digit * start * 9;
        }
        long num = start + (n - 1)/digit;
        return Long.toString(num).charAt((n - 1) % digit) - '0';

    }
}

image.png

剑指 Offer 45. 把数组排成最小的数

image.png
image.png

class Solution {
    public String minNumber(int[] nums) {
        String[] str = new String[nums.length];
        for(int i = 0; i < nums.length; i++){
            str[i] = String.valueOf(nums[i]);
        }

        //字符串排序
        strsort(str, 0, str.length - 1);
        //Arrays.sort(str, (x,y) -> (x+y).compareTo(y+x));//内置函数
        StringBuilder res  = new StringBuilder();
        for(String s : str){
            res.append(s);
        }
        return res.toString();
    }

    public void strsort(String[] str, int l, int r){
        if(l >= r) return ;
        int i = l, j = r;
        String temp = str[i];
        while(i < j){
            while((str[j] + str[l]).compareTo(str[l] + str[j]) >= 0 && i < j) j--;
            while((str[i] + str[l]).compareTo(str[l] + str[i]) <= 0 && i < j) i++;
            temp = str[i];
            str[i] = str[j];
            str[j] = temp;
        }

        str[i] = str[l];
        str[l] = temp;
        strsort(str, l, i - 1);
        strsort(str, i + 1, r);
    }
}

剑指 Offer 46. 把数字翻译成字符串

image.png

class Solution {
    public int translateNum(int num) {
        //0 ~ 25
        //dp[i] = dp[i -1] + dp[i -2]
        String s = String.valueOf(num);
        int a = 1, b  = 1;
        for(int i = 2; i <= s.length(); i++){
            String temp = s.substring(i - 2, i);
            int c = temp.compareTo("10") >= 0 && temp.compareTo("25") <= 0 ? a+b :a;
            b = a;
            a = c; 
        }
        return a;
    }
}

剑指 Offer 47. 礼物的最大价值

image.png

class Solution {
    public int maxValue(int[][] grid) {
        //最经典二维动态规划
        //f[i][j] = max(f[i-1][j], f[i][j - 1])
        int m = grid.length, n = grid[0].length;
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(i == 0 && j == 0) continue;
                if( i == 0){
                    grid[i][j] += grid[i][j - 1];
                } 
                else if(j == 0){
                    grid[i][j] += grid[i - 1][j];
                }else{
                    grid[i][j] += Math.max(grid[i - 1][j], grid[i][j - 1]);
                }
            }
        }
        return grid[m - 1][n - 1];
    }
}

剑指 Offer 48. 最长不含重复字符的子字符串

image.png

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> hash = new HashMap<>();
        int res = 0, left = 0;
        for(int i = 0; i< s.length(); i++){
            char c = s.charAt(i);
            //判断c是否出现过
            if(hash.containsKey(c)){
                left = Math.max(left, hash.get(c) + 1);
            }
            hash.put(c, i);
            res = Math.max(res, i - left + 1);
        }
        return res;
    }
}

剑指 Offer 49. 丑数

image.png

class Solution {
    public int nthUglyNumber(int n) {
        int[] f = new int[n];     //前n个丑数
        int[] pos = new int[3];   //对应2 3 5 三个质因子
        f[0] = 1;                 //第一个丑数
        for(int i = 1; i < n; i++){
            int a = f[pos[0]] * 2;
            int b = f[pos[1]] * 3;
            int c = f[pos[2]] * 5;
            int mini = Math.min(Math.min(a,b),c);
            if(f[pos[0]] * 2 == mini) pos[0]++;
            if(f[pos[1]] * 3 == mini) pos[1]++;
            if(f[pos[2]] * 5 == mini) pos[2]++;
            f[i] = mini;
        }
        return f[n - 1];
    }
}

剑指 Offer 50. 第一个只出现一次的字符

image.png

class Solution {
    public char firstUniqChar(String s) {
        HashMap<Character, Boolean> hash = new HashMap<>();
        char[] ch = s.toCharArray();
        for(char c : ch){
            hash.put(c, !hash.containsKey(c)); //先插入true, 重复插入为false
        }
        for(char c : ch){
            if(hash.get(c)){
                return c;
            }
        }
        return ' ';

    }
}

剑指 Offer 51. 数组中的逆序对

image.png
image.png

class Solution {
    int[] nums, tmp;
    public int reversePairs(int[] nums) {
        this.nums = nums;
        tmp = new int[nums.length];
        return mergeSort(0, nums.length - 1);
    }
    private int mergeSort(int l, int r) {
        // 终止条件
        if (l >= r) return 0;
        // 递归划分
        int m = (l + r) / 2;
        int res = mergeSort(l, m) + mergeSort(m + 1, r);
        // 合并阶段
        int i = l, j = m + 1;
        for (int k = l; k <= r; k++)
            tmp[k] = nums[k];
        for (int k = l; k <= r; k++) {
            if (i == m + 1)
                nums[k] = tmp[j++];
            else if (j == r + 1 || tmp[i] <= tmp[j])
                nums[k] = tmp[i++];
            else {
                nums[k] = tmp[j++];
                res += m - i + 1; // 统计逆序对
            }
        }
        return res;
    }
}

剑指 Offer 52. 两个链表的第一个公共节点

image.png
image.png

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode idxA = headA;
        ListNode idxB = headB;
        while(idxA != idxB){
            if(idxA == null){
                idxA  =headB;
            }else{
                idxA = idxA.next;
            }

            if(idxB == null){
                idxB = headA;
            }else{
                idxB = idxB.next;
            }
        }
        return idxA;

    }
}

剑指 Offer 53 - I. 在排序数组中查找数字 I

image.png

class Solution {
    public int search(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return 0;
        }

        int start = binarySearch(nums, target);
        int  end = binarySearch(nums, target + 1);
        return end - start + (nums[end] == target ? 1 : 0);
    }

    private int binarySearch(int[] nums, int tar){
        int l = 0, r = nums.length - 1;
        while(l < r){
            int mid = l + (r  - l)/2;
            if(nums[mid] < tar){
                l = mid + 1;
            }else{
                r = mid;
            }
        }
        return l;
    }
}

剑指 Offer 53 - II. 0~n-1中缺失的数字

image.png
image.png

class Solution {
    public int missingNumber(int[] nums) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        int l = 0; 
        int r = nums.length  - 1;
        while(l < r){
            int mid = l + (r - l) / 2;
            if(nums[mid] != mid){
                r = mid;
            }else{
                l  = mid + 1;
            }
        }
        if(nums[r] == r){
            r++;
        }
        return r;

    }
}

剑指 Offer 54. 二叉搜索树的第k大节点

image.png
image.png

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {

    int k1, res;
    public int kthLargest(TreeNode root, int k) {
        k1 = k;
        dfs(root);
        return res;
    }

    private void dfs(TreeNode root){
        if(root == null || k1 == 0){
            return;
        }
        dfs(root.right);  //右子树
        if(--k1 == 0) res = root.val;  //根节点
        dfs(root.left);   //左子树

    }
}

剑指 Offer 55 - I. 二叉树的深度

image.png

/**
 * 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;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return left > right ? left + 1 : right + 1;
    }
}

剑指 Offer 55 - II. 平衡二叉树

image.png

/**
 * 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;
        }
        int left = treeDepth(root.left);
        int right = treeDepth(root.right);
        return Math.abs(left - right) > 1 ? false : true && isBalanced(root.left) &&
        isBalanced(root.right);
    }

    //树的深度
    public int treeDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        int a = treeDepth(root.left);
        int b = treeDepth(root.right);
        return a > b ? a + 1:b + 1;
    }
}

剑指 Offer 56 - I. 数组中数字出现的次数

image.png

class Solution {
    public int[] singleNumbers(int[] nums) {
        //1.数组中只出现一次的两个数字的异或结果
        int sum = 0;
        for(int x : nums){
            sum ^= x;
        }
        //2.找到异或二进制中1所在的位置
        int index = 0;
        while((sum >> index & 1) == 0){
            index++;
        }
        int first = 0;
        for(int x : nums){
            if((x >> index & 1) == 0){
                first ^= x;
            }
        }
        int second = sum ^ first;
        return new int[]{first, second};
    }
}

剑指 Offer 56 - II. 数组中数字出现的次数 II

image.png
image.png

class Solution {
    public int singleNumber(int[] nums) {
        int[] count = new int[32];
        for(int num : nums){
            for(int i = 0; i < 32; i++){
                count[i] += num & 1;
                num >>= 1;
            }
        }
        int res = 0, mod = 3;
        for(int i = 0; i< 32; i++){
            res <<= 1;
            res += count[31 - i] % mod;
        }
        return res;

    }
}

剑指 Offer 57. 和为s的两个数字

image.png
image.png

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i = 0;
        int 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 null;
    }
}

class Solution{
    public int[] twoSum(int[] nums, int target){
        Set<Integer> s = new HashSet<>();
        for(int i = 0; i < nums.length; i++){
            s.add(nums[i]);
        }
        for(int i = 0; i < nums.length; i++){
            if(s.contains(target - nums[i])){
                return new int[]{nums[i], target - nums[i]};
            }
        }
        return null;
    }
}

剑指 Offer 57 - II. 和为s的连续正数序列

image.png

class Solution {
    public int[][] findContinuousSequence(int target) {
        int i = 1;
        int j = 1;
        int sum = 0;
        List<int[]> res = new ArrayList<>();
        while(i <= target / 2){
            if(sum < target){  
                sum += j;     //右边界向右移动
                j++;
            }else if(sum > target){
                sum -= i;    //左边界向右移动
                i++;
            }else{
                int[] arr = new int[j - i];
                for(int k = i; k < j; k++){
                    arr[k -i] = k;
                }
                res.add(arr);
                sum -= i;      //左边界向右移动
                i++;
            }
        }
        return res.toArray(new int[res.size()][]);
    }
}

剑指 Offer 58 - I. 翻转单词顺序

image.png

class Solution {
    public String reverseWords(String s) {
        s = s.trim(); //去除收尾空格
        int j = s.length() - 1, i = j;
        StringBuilder res = new StringBuilder();
        while(i >= 0){
            while(i >= 0 && s.charAt(i) != ' ') i--; //找到空格
            res.append(s.substring(i + 1, j + 1) + " "); //添加单词
            while(i >= 0 && s.charAt(i) == ' ') i--;     //跳过空格
            j = i;
        }
        return res.toString().trim();
    }
}

剑指 Offer 58 - II. 左旋转字符串

image.png

class Solution {
    public String reverseLeftWords(String s, int n) {
        String res = "";
        for(int i = n; i < s.length(); i++)
            res += s.charAt(i);
        for(int i = 0; i < n; i++)
            res += s.charAt(i);
        return res;
    }
}

剑指 Offer 59 - I. 滑动窗口的最大值

image.png
image.png

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 0 || k == 0){
            return new int[0];
        }
        int[] res  =new int[nums.length - k + 1];
        Deque<Integer> q = new LinkedList<>();
        int j = 0;
        for(int i = 0; i < nums.length; i++){
            if(q.size() > 0 && i - q.peekFirst() >= k){ //判断队头是否需要出队
                q.pollFirst();
            } 
            while(q.size() > 0 && nums[q.peekLast()] < nums[i]){
                q.pollLast();
            }
            q.add(i);
            if(i >= k - 1){
                res[j++] = (nums[q.peekFirst()]); //取队头作为窗口最大元素
            }
        }
        return res;

    }
}

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        //边界条件判断
    if (nums == null || nums.length == 0)
        return new int[0];
    int res[] = new int[nums.length - k + 1];
    for (int i = 0; i < res.length; i++) {
        int max = nums[i];
        //在每个窗口内找到最大值
        for (int j = 1; j < k; j++) {
            max = Math.max(max, nums[i + j]);
        }
        res[i] = max;
    }
    return res;
    }
}

剑指 Offer 59 - II. 队列的最大值

image.png
image.png
image.png
image.png

class MaxQueue {
    Queue<Integer> que;
    Deque<Integer> deq; //记录最大值

    public MaxQueue() {
        que = new LinkedList<>();
        deq = new LinkedList<>();

    }

    public int max_value() {
        //取双端队列的队首作为最大值
        return deq.size() > 0 ? deq.peek() : -1;

    }

    public void push_back(int value) {
        que.add(value);
        while(deq.size() > 0 && deq.peekLast() < value){
            deq.pollLast(); //保证双端队列存的就是最大的值,将队尾小于value的元素全部删除
        }
        deq.add(value);

    }

    public int pop_front() {
        int v = que.size() > 0 ? que.poll() : -1;
        if(deq.size() > 0 && deq.peekFirst() == v){
            deq.pollFirst();
        }
        return v;

    }
}

/**
 * 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();
 */

剑指 Offer 60. n个骰子的点数

image.png

class Solution {
    public double[] dicesProbability(int n) {
        double all = Math.pow(6, n);  //方案总数
        int[][] dp = new int[n + 1][6*n + 1];  //状态数组
        dp[0][0] = 1;
        //dp[i][j]有i个骰子,点数和为j的方案总数
        for(int i = 1; i <= n; i++){ //n个骰子
            for(int j = 1; j <= 6 * i; j++){
                for(int k = 1; k <= Math.min(j, 6); k++){
                    dp[i][j] += dp[i - 1][j - k]; //前i次总和为j的方案总数
                }
            }
        }
        double[] res = new double[1 + 5 * n];
        for(int i = n; i <= n * 6; i++){
            res[i - n] = dp[n][i] / all;  //转换成概率
        }
        return res;

    }
}

剑指 Offer 61. 扑克牌中的顺子

image.png

class Solution {
    public boolean isStraight(int[] nums) {
        if(nums.length != 5){
            return false;
        }

        Arrays.sort(nums);    // 0 0 xxxxx
        int k  = 0;           //去除0  nums[k] != 0
        while(nums[k] == 0){
            k++;
        }
        for(int i = k + 1; i < nums.length; i++){  //查看有无重复数字
            if(nums[i] == nums [i - 1]){
                return false;
            }
        }
        return nums[4] - nums[k] <= 4;            //最小 <= 4;

    }
}

剑指 Offer 62. 圆圈中最后剩下的数字

image.png
image.png

class Solution {
    public int lastRemaining(int n, int m) {
        if(n == 1){
            return 0;
        }
        return (lastRemaining(n - 1, m) + m) % n;

    }
}

剑指 Offer 63. 股票的最大利润

image.png

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length == 0){
            return 0;
        }
        int maxv = 0;                //最大利润
        int minv = prices[0];        //最小价格,默认第一个最小
        for(int i = 1; i < prices.length; i++){
            maxv = Math.max(prices[i] - minv, maxv);
            minv =  Math.min(minv, prices[i]);
        }
        return maxv;
    }
}

剑指 Offer 64. 求1+2+…+n

image.png

class Solution {
    public int sumNums(int n) {
        return n == 0 ? 0 : n + sumNums(n - 1);

    }
}

剑指 Offer 65. 不用加减乘除做加法

image.png

class Solution {
    public int add(int a, int b) {
        while( b != 0){
            int c = (a & b) << 1; //c进位
            a ^= b;                //a非进位部分的和
            b = c;
        }
        return a;
    }
}

剑指 Offer 66. 构建乘积数组

image.png

class Solution {
    public int[] constructArr(int[] a) {
        //避开在i时避开 x ai
        int n = a.length;
        int[] res = new int[n];
        for(int i = 0, p = 1; i < n; i++){
            res[i] = p;            //a1 ***** ai - 1
            p *= a[i];
        }
        for(int i = n - 1, p = 1; i >= 0; i--){
            res[i] *= p;           //ai + 1 ***** an -1
            p *= a[i]; 
        }
        return res;

    }
}

剑指 Offer 67. 把字符串转换成整数

image.png

class Solution {
    public int strToInt(String str) {
        char[] c = str.trim().toCharArray();
        if(c.length == 0){
            return 0;
        }

        int res = 0, sign = 1;  //res返回结果 sign 1正数  -1负数
        int temp = Integer.MAX_VALUE / 10;
        int index = 1;
        if(c[0] == '-'){
            sign = -1;
        }else if(c[0] != '+'){
            index = 0;
        }
        for(int i = index; i < c.length; i++){
            if(c[i] < '0' || c[i] > '9') break;
            if(res > temp || (res == temp && c[i] > '7')){
                return sign == 1 ? Integer.MAX_VALUE: Integer.MIN_VALUE;
            }
            res = res * 10 + c[i] - '0';
        }
        return sign * (int)res;

    }
}

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

image.png
image.png

/**
 * 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(p.val > q.val){
            TreeNode temp = p;
            p = q;
            q = temp;
        }

        while(root != null){
            if(root.val < p.val){
                root = root.right;
            }else if(root.val > q.val){
                root = root.left;
            }else{
                break;
            }
        }
        return root;
    }
}


class Solution{
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        if(root.val < p.val && root.val < q.val){
            return lowestCommonAncestor(root.right, p, q);
        }
        if(root.val > p.val && root.val > q.val){
            return lowestCommonAncestor(root.left, p, q);
        }
        return root;
    }
}

剑指 Offer 68 - II. 二叉树的最近公共祖先

image.png

/**
 * 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;
    }
}