【剑指Offer】Java题解汇总

【剑指Offer】Java题解汇总

01. 数组中重复的数字
class Solution {
    public int findRepeatNumber(int[] nums) {
        for(int i = 0;i < nums.length; i++){
            while(nums[i] != i){
                if(nums[i] == nums[nums[i]]){
                    return nums[i];
                } else {
                    int temp = nums[i];
                    nums[i] = nums[temp];
                    nums[temp] = temp;
                }
            }
        }
        return -1;
    }
}
02. 二维数组中的查找
class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix.length == 0){
            return false;
        }

        int row = 0;
        int col = matrix[0].length-1;

        while(row < matrix.length && col >= 0){
            if(target == matrix[row][col]){
                return true;
            } else if(target > matrix[row][col]) {
                row ++;
            } else if(target < matrix[row][col]) {
                col --;
            }
        }
        return false;
    }
}
03. 替换空格
// class Solution {
//     public String replaceSpace(String s) {
//         return s.replaceAll(" ","%20");
//     }
// }

class Solution{
    public String replaceSpace(String s) {
        if(s == null){
            return null;
        }

        int cnt = 0;
        for(int i = 0;i < s.length();i++){
            if(s.charAt(i) == ' '){
                cnt ++;
            }
        }

        cnt = s.length() + cnt * 2;

        char[] s_char = new char[cnt];

        int p1 = s.length()-1;
        int p2 = cnt-1;

        while(p1>=0 && p2>=0){
            if(s.charAt(p1) != ' '){
                s_char[p2] = s.charAt(p1);
                p2 --;
                p1 --;
            } else{
                s_char[p2] = '0';
                p2 --;
                s_char[p2] = '2';
                p2 --;
                s_char[p2] = '%';
                p2 --;
                p1 --;
            }
        }
        return new String(s_char);
    }
}
04. 从尾到头打印链表
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */

 //用栈的方法
class Solution {
    public int[] reversePrint(ListNode head) {
        if(head == null){
            return new int[]{};
        }
        ListNode temp = head;

        Stack<ListNode> stack = new Stack<ListNode>();
        while(temp != null){
            stack.push(temp);
            temp = temp.next;
        }

        int size = stack.size();
        int[] vec = new int[size];
        for(int i = 0;i < size;i++){
            vec[i] = stack.pop().val;
        }
        return vec;
    }
}
05. 重建二叉树

官方:

方法一:递归
二叉树的前序遍历顺序是:根节点、左子树、右子树,每个子树的遍历顺序同样满足前序遍历顺序。

二叉树的中序遍历顺序是:左子树、根节点、右子树,每个子树的遍历顺序同样满足中序遍历顺序。

前序遍历的第一个节点是根节点,只要找到根节点在中序遍历中的位置,在根节点之前被访问的节点都位于左子树,在根节点之后被访问的节点都位于右子树,由此可知左子树和右子树分别有多少个节点。

由于树中的节点数量与遍历方式无关,通过中序遍历得知左子树和右子树的节点数量之后,可以根据节点数量得到前序遍历中的左子树和右子树的分界,因此可以进一步得到左子树和右子树各自的前序遍历和中序遍历,可以通过递归的方式,重建左子树和右子树,然后重建整个二叉树。

使用一个 Map 存储中序遍历的每个元素及其对应的下标,目的是为了快速获得一个元素在中序遍历中的位置。调用递归方法,对于前序遍历和中序遍历,下标范围都是从 0 到 n-1,其中 n 是二叉树节点个数。

递归方法的基准情形有两个:判断前序遍历的下标范围的开始和结束,若开始大于结束,则当前的二叉树中没有节点,返回空值 null。若开始等于结束,则当前的二叉树中恰好有一个节点,根据节点值创建该节点作为根节点并返回。

若开始小于结束,则当前的二叉树中有多个节点。在中序遍历中得到根节点的位置,从而得到左子树和右子树各自的下标范围和节点数量,知道节点数量后,在前序遍历中即可得到左子树和右子树各自的下标范围,然后递归重建左子树和右子树,并将左右子树的根节点分别作为当前根节点的左右子节点。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0) {
            return null;
        }
        Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
        int length = preorder.length;
        for (int i = 0; i < length; i++) {
            indexMap.put(inorder[i], i);
        }
        TreeNode root = buildTree(preorder, 0, length - 1, inorder, 0, length - 1, indexMap);
        return root;
    }

    public TreeNode buildTree(int[] preorder, int preorderStart, int preorderEnd, int[] inorder, int inorderStart, int inorderEnd, Map<Integer, Integer> indexMap) {
        if (preorderStart > preorderEnd) {
            return null;
        }
        int rootVal = preorder[preorderStart];
        TreeNode root = new TreeNode(rootVal);
        if (preorderStart == preorderEnd) {
            return root;
        } else {
            int rootIndex = indexMap.get(rootVal);
            int leftNodes = rootIndex - inorderStart, rightNodes = inorderEnd - rootIndex;
            TreeNode leftSubtree = buildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inorderStart, rootIndex - 1, indexMap);
            TreeNode rightSubtree = buildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, indexMap);
            root.left = leftSubtree;
            root.right = rightSubtree;
            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 TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || preorder.length == 0){
            return null;
        }

        int length = preorder.length;
        Map<Integer,Integer> indexMap = new HashMap<Integer,Integer>();
        for(int i=0; i<length; i++){
            indexMap.put(inorder[i],i);
        }

        TreeNode root = rebuildTree(preorder,0,length-1,inorder,0,length-1,indexMap);
        return root;

    }

    public TreeNode rebuildTree(int[] preorder,int start_pre,int end_pre,int[] inorder,int start_in,int end_in,Map<Integer,Integer> indexMap){
        if(start_pre > end_pre){
            return null;
        }

        int rootVal = preorder[start_pre];
        TreeNode root = new TreeNode(rootVal);
        if(start_pre == end_pre){
            return root;
        } else {
            int index = indexMap.get(root.val);
            int leftNodes = index - start_in;
            int rightNodes = end_in - index;
            TreeNode leftTree = rebuildTree(preorder,start_pre+1,start_pre+leftNodes,inorder,start_in,index-1,indexMap);
            TreeNode rightTree = rebuildTree(preorder,start_pre+leftNodes+1,end_pre,inorder,index+1,end_in,indexMap);
            root.left = leftTree;
            root.right = rightTree;
            return root;
        }
    }
}
06. 用两个栈实现队列
class CQueue {

    Stack<Integer> stack1;
    Stack<Integer> stack2;

    public CQueue() {
        stack1 = new Stack<Integer>();
        stack2 = new Stack<Integer>();
    }
    
    public void appendTail(int value) {
        stack1.push(value);
    }
    
    public int deleteHead() {
        if(!stack2.empty()){
            return stack2.pop();
        } else {
            if(stack1.empty()){
                return -1;
            } else{
                while(!stack1.empty()){
                    stack2.push(stack1.pop());
                }
                return stack2.pop();
            }
        }
    }
}

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */
07. 斐波那契数列
class Solution {
    public int fib(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1){
            return 1;
        }
        int f0 = 0;
        int f1 = 1;
        int fn = 0;
        for(int i=1; i<n;i++){
            fn = (f0 + f1) % 1000000007;
            f0 = f1;
            f1 = fn;
        }
        return fn;
    }
}
08. 青蛙跳台阶问题

类似于斐波那契数列

class Solution {
    public int numWays(int n) {
        if(n == 1 || n==0){
            return 1;
        }
        if(n == 2){
            return 2;
        }

        int fn_1 = 1;
        int fn_2 = 2;
        int fn_3 = 0;

        for(int i=2; i<n; i++){
            fn_3 = (fn_1+fn_2) % 1000000007;
            fn_1 = fn_2;
            fn_2 = fn_3;
        }
        return fn_3;
    }
}
09. 旋转数组的最小数字
class Solution {
    public int minArray(int[] numbers) {
        int index1 = 0;
        int index2 = numbers.length-1;
        int indexMid;
        if(numbers[index1] < numbers[index2]){
            return numbers[index1];
        }

        while((index2-index1) > 1){
            indexMid = (index1+index2)/2;

            //如果index1和index2和indexMid的值都一样,就只能用顺序查找了
            if(numbers[index1] == numbers[index2] && numbers[index2] == numbers[indexMid]){
                int res = numbers[index1];
                for(int i=index1+1; i<=index2; i++){
                    if(res > numbers[i]){
                        res = numbers[i];
                    }
                }
                return res;
            }

            if(numbers[indexMid] >= numbers[index1]){
                index1 = indexMid;
            } else if(numbers[indexMid] <= numbers[index2]){
                index2 = indexMid;
            }
        }
        return numbers[index2];
    }
}
10. 矩阵中的路径

还有一些问题:

class Solution {
    public boolean exist(char[][] board, String word) {
        int rows = board.length;
        int cols = board[0].length;
        int wordLength = word.length();

        if(wordLength>(rows*cols)){
            return false;
        }

        boolean[][] map = new boolean[rows][cols];
        boolean flag = false;;
        for(int row=0; row<rows; row++){
            for(int col=0; col<cols; col++){
                if(board[row][col] == word.charAt(0)){
                    flag = hasPath(board,row,col,map,0,word);
                }
                if(flag == true){
                    return true;
                }
            }
        }
        return false;
    }

    public boolean hasPath(char[][] board, int i, int j, boolean[][] map, int wordIndex, String word){
        if((wordIndex+1) == word.length()){
            return true;
        } else {
            if(i>=0 && i<board.length && j>=0 && j<board[0].length && map[i][j] == false && board[i][j]==word.charAt(wordIndex)){
                map[i][j] = true;
                wordIndex ++;
                if(hasPath(board,i+1,j,map,wordIndex,word)){
                    return true;
                } else if(hasPath(board,i-1,j,map,wordIndex,word)){
                    return true;
                } else if(hasPath(board,i,j+1,map,wordIndex,word)){
                    return true;
                } else if(hasPath(board,i,j-1,map,wordIndex,word)){
                    return true;
                } else{
                    return false;
                }
            } else{
                return false;
            }
        }
    }
}
11. 机器人的运动范围
class Solution {
    public int movingCount(int m, int n, int k) {
        boolean[] visited = new boolean[m*n];
        int cnt = mcount(m,n,k,0,0,visited);
        return cnt;
    }

    public int mcount(int m, int n, int k, int row, int col, boolean[] visited){
        int cnt = 0;
        if(check(m,n,k,row,col,visited)){
            visited[row*n+col] = true;
            cnt = 1+mcount(m,n,k,row-1,col,visited) + mcount(m,n,k,row+1,col,visited) + mcount(m,n,k,row,col-1,visited) + mcount(m,n,k,row,col+1,visited);
        }
        return cnt;

    }

    public boolean check(int m, int n, int k, int row, int col, boolean[] visited){
        if(row>=0 && row<m && col>=0 && col<n && getSum(row,col)<=k && !visited[row*n+col]){
            return true;
        }
        return false;
    }

    public int getSum(int row, int col){
        int sum = 0;
        while(row > 0){
            sum = sum + row%10;
            row = row/10;
        }
        while(col > 0){
            sum = sum + col%10;
            col = col/10;
        }
        return sum;
    }
}
12. 剪绳子<动态规划>
class Solution {
    public int cuttingRope(int n) {
        if(n < 2){
            return 0;
        }
        if(n == 2){
            return 1;
        }
        if(n == 3){
            return 2;
        }

        int[] products = new int[n+1];
        products[0] = 0;
        //这里的原因是,如果长度是1、2、3时就不要切分了,因为分了以后更小了
        products[1] = 1;
        products[2] = 2;
        products[3] = 3;

        int max = 0;
        for(int i=4; i<=n; i++){
            max = 0;
            for(int j=1; j<=i/2; j++){
                int product = products[j]*products[i-j];
                if(max < product){
                    max = product;
                }
            }
            products[i] = max;
        }
        return products[n];
    }
}
13. 剪绳子<贪心算法,大数取余>

参考详解:https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/solution/mian-shi-ti-14-ii-jian-sheng-zi-iitan-xin-er-fen-f/

class Solution {
    public int cuttingRope(int n) {
        if(n < 2){
            return 0;
        }
        if(n == 2){
            return 1;
        }
        if(n == 3){
            return 2;
        }

        //尽可能多的减去长度为3的绳子段
        int time3 = n/3;

        if(n - time3*3 == 1){
            time3 = time3-1;
        }

        int time2 = (n-time3*3)/2;
        long res = 1;
        //循环取余
        for(int i=0; i<time3; i++){
            res = (res * 3) % 1000000007;
        }
        for(int i=0; i<time2; i++){
            res = (res * 2) % 1000000007;
        }

        // long res = (long)(Math.pow(3,time3)) * (long)(Math.pow(2,time2)) % 1000000007;
        return (int)res;
    }
}
14. 二进制中1的个数

Java提供的位运算符有:左移( << )、右移( >> ) 、无符号右移( >>> ) 、位与( & ) 、位或( | )、位非( ~ )、位异或( ^ )

方法一:

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        while(n != 0){
            if((n&1) == 1){
                count ++;
            }
            n= n>>>1;
        }
        return count;
    }
}

牛皮方法二:

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        /*
        int count = 0;
        while(n != 0){
            if((n&1) == 1){
                count ++;
            }
            n= n>>>1;
        }
        return count;
        */
        int count = 0;
        while(n != 0){
            count ++;
            n = (n-1)&n;
        }
        return count;
    }
}
15. 数值的整数次方

参考大佬:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/solution/mian-shi-ti-16-shu-zhi-de-zheng-shu-ci-fang-kuai-s/

/*class Solution {
    public double myPow(double x, int n) {
        if((x-0.0) < 0.00000001 && n < 0){
            return 0.0;
        }
        if(n == 0){
            return 1.0;
        }
        if(n < 0){
            double res = 1.0 / powerWithPositiveEx(x,-n);
            return res;
        } 
        double res = powerWithPositiveEx(x,n);
        return res;
        


    }
    /*普通做法
    public double powerWithPositiveEx(double x, int n){
        double res = 1.0;
        for(int i=0; i<n; i++){
            res = res * x;
        }
        return res;
    }
    *//*
    public double powerWithPositiveEx(double x, int n){
        int cnt = (int)(Math.log(n)/Math.log(2)) - 1;
        double res = x;
        for(int i=1; i<cnt; i++){
            res = res*res;
        }
        if(n%2 == 1){
            res = res*x;
        }
        return res;
    }
}*/
class Solution {
    public double myPow(double x, int n) {
        if(x == 0) return 0;
        long b = n;
        double res = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) res *= x;
            x *= x;
            b >>= 1;
        }
        return res;
    }
}
16. 打印从1到最大的n位数(大数问题)
class Solution {
    int res[];
    int index = 0;

    public int[] printNumbers(int n) {
        if(n <= 0){
            return new int[]{};
        }
        char[] number = new char[n];
        res = new int[(int)Math.pow(10, n) - 1];

        for(int i=0; i<10; i++){
            number[0] = (char)(i+'0');
            printToMax(number,n,0);
        }
        return res;
    }
    public void printToMax(char[] number, int length, int index){
        if(index == length-1){
            printIntoInt(number);
            return;
        }
        for(int i=0; i<10; i++){
            number[index+1] = (char)(i+'0');
            printToMax(number,length,index+1);
        }
    }
    public void printIntoInt(char[] number){
        int nLength = number.length;
        int result = 0;
        int j = 1;
        for(int i=nLength-1; i>=0; i--,j*=10){
            result = result + (number[i]-'0')*j;
        }
        if(result != 0){
            res[index] = result;
            index ++;
        }
        
    }
}
17. 删除链表的节点
/**
 * 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 == null){
            return head;
        }
        //只有一个节点,正好要删除他
        if(head.next == null && head.val == val){
            return null;
        }
        //要删除头节点
        if(head.val == val){
            return head.next;
        }
        ListNode temp = head;
        while(temp != null && temp.next != null){
            if(temp.next.val == val){
                temp.next = temp.next.next;
            }
            temp = temp.next;
        }
        return head;

    }
}
18. 正则表达式匹配(Hard)

有递归和动态规划两种方法,这里只有递归

/*有问题
class Solution {
    public boolean isMatch(String s, String p) {
        if(s == null || p == null){
            return false;
        }
        int sIndex = 0;
        int pIndex = 0;
        return matchCore(s,p,sIndex,pIndex);
    }
    public boolean matchCore(String s, String p, int sIndex, int pIndex){
        if(sIndex >= s.length()-1 && pIndex >= p.length()-1){
            return true;
        }
        if(sIndex != s.length()-1 && pIndex == p.length()-1){
            return false;
        }
        if((pIndex+1)<p.length() && p.charAt(pIndex+1) == '*'){
            if(p.charAt(pIndex) == s.charAt(sIndex) || (p.charAt(pIndex) == '.' && sIndex != s.length()-1)){
                return matchCore(s,p,sIndex+1,pIndex+2) || matchCore(s,p,sIndex+1,pIndex) || matchCore(s,p,sIndex,pIndex+2);
            } else {
                return matchCore(s,p,sIndex,pIndex+2);
            }
        }
        if(s.charAt(sIndex) == p.charAt(pIndex) || (p.charAt(pIndex) == '.' && sIndex != s.length()-1)){
            return matchCore(s,p,sIndex+1,pIndex+1);
        }
        return false;
    }
}
*/
class Solution {
    public boolean isMatch(String A, String B) {
        // 如果字符串长度为0,需要检测下正则串
        if (A.length() == 0) {
            // 如果正则串长度为奇数,必定不匹配,比如 "."、"ab*",必须是 a*b*这种形式,*在奇数位上
            if (B.length() % 2 != 0) return false;
            int i = 1;
            while (i < B.length()) {
                if (B.charAt(i) != '*') return false;
                i += 2;
            }
            return true;
        }
        // 如果字符串长度不为0,但是正则串没了,return false
        if (B.length() == 0) return false;
        // c1 和 c2 分别是两个串的当前位,c3是正则串当前位的后一位,如果存在的话,就更新一下
        char c1 = A.charAt(0), c2 = B.charAt(0), c3 = 'a';
        if (B.length() > 1) {
            c3 = B.charAt(1);
        }
        // 和dp一样,后一位分为是 '*' 和不是 '*' 两种情况
        if (c3 != '*') {
            // 如果该位字符一样,或是正则串该位是 '.',也就是能匹配任意字符,就可以往后走
            if (c1 == c2 || c2 == '.') {
                return isMatch(A.substring(1), B.substring(1));
            } else {
                // 否则不匹配
                return false;
            }
        } else {
            // 如果该位字符一样,或是正则串该位是 '.',和dp一样,有看和不看两种情况
            if (c1 == c2 || c2 == '.') {
                return isMatch(A.substring(1), B) || isMatch(A, B.substring(2));
            } else {
                // 不一样,那么正则串这两位就废了,直接往后走
                return isMatch(A, B.substring(2));
            }
        }
    }
}

19. 表示数值的字符串
class Solution {
    private int index = 0;//全局索引
    private boolean scanUnsignedInteger(String str) {
        //是否包含无符号数
        int before = index;
        while(str.charAt(index) >= '0' && str.charAt(index) <= '9') 
            index++;
        return index > before;
    }
    private boolean scanInteger(String str) {
        //是否包含有符号数
        if(str.charAt(index) == '+' || str.charAt(index) == '-') 
               index++;
        return scanUnsignedInteger(str);
    }
    public boolean isNumber(String s) {
        //空字符串
        if(s == null || s.length() == 0)
            return false;
        //添加结束标志
        s = s + '|';
        //跳过首部的空格
        while(s.charAt(index) == ' ')
            index++;
        boolean numeric = scanInteger(s); //是否包含整数部分
        if(s.charAt(index) == '.') {  
            index++;
            //有小数点,处理小数部分
            //小数点两边只要有一边有数字就可以,所以用||,
            //注意scanUnsignedInteger要在前面,否则不会进
            numeric = scanUnsignedInteger(s) || numeric;
        }
        if((s.charAt(index) == 'E' || s.charAt(index) == 'e')) { 
            index++;
            //指数部分
            //e或E的两边都要有数字,所以用&&
            numeric = numeric && scanInteger(s);
        }
        //跳过尾部空格
        while(s.charAt(index) == ' ')
            index++;
        return numeric && s.charAt(index) == '|' ;
    }
}
20. 调整数组顺序使奇数位于偶数前面
class Solution {
    public int[] exchange(int[] nums) {
        if(nums.length == 0 ||nums.length == 1){
            return nums;
        }
        int indexOne = 0;
        int indexTwo = nums.length-1;
        while(indexTwo > indexOne){
            while(indexOne < indexTwo && nums[indexOne]%2 != 0){
                indexOne ++;
            }
            while(indexTwo > indexOne && nums[indexTwo]%2 != 1){
                indexTwo --;
            }
            if(indexTwo <= indexOne){
                break;
            }
            int temp = nums[indexOne];
            nums[indexOne] = nums[indexTwo];
            nums[indexTwo] = temp;
            indexOne ++;
            indexTwo --;
        }
        return nums;
    }
}
21. 链表中倒数第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 || k == 0){
            return null;
        }
        ListNode tempOne = head;
        ListNode tempTwo = head;
        for(int i=0; i<k-1; i++){
            if(tempOne.next != null){
                tempOne = tempOne.next;
            } else {
                return null;
            }
        }
        while(tempOne.next != null){
            tempOne = tempOne.next;
            tempTwo = tempTwo.next;
        }
        return tempTwo;
    }
}
22. 反转链表

用的是一个个嵌进去的方法,参考尚学堂数据结构课

/**
 * 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 reverseHead = new ListNode(-1);
        ListNode tempOri = head;
        ListNode tempNext;
        while(tempOri != null){
            tempNext = tempOri.next;
            tempOri.next = reverseHead.next;
            reverseHead.next = tempOri;
            if(tempNext == null){
                break;
            }
            tempOri = tempNext;
            tempNext = tempNext.next;
        }
        return reverseHead.next;
    }
}
23. 合并两个排序的链表

循环迭代:

/**
 * 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;
        }
        if(l2 == null){
            return l1;
        }

        ListNode preHead = new ListNode(-1);
        ListNode temp = preHead;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                temp.next = l1;
                temp = temp.next;
                l1 = l1.next;
            } else {
                temp.next = l2;
                temp = temp.next;
                l2 = l2.next;
            }
        }
        if(l1 == null){
            temp.next = l2;
        } else{
            temp.next = l1;
        }
        return preHead.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;
        }
        if(l2 == null){
            return l1;
        }

        ListNode preHead = new ListNode(-1);
        ListNode temp = preHead;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                temp.next = l1;
                temp = temp.next;
                l1 = l1.next;
            } else {
                temp.next = l2;
                temp = temp.next;
                l2 = l2.next;
            }
        }
        if(l1 == null){
            temp.next = l2;
        } else{
            temp.next = l1;
        }
        return preHead.next;
        */

        if(l1 == null){
            return l2;
        }
        if(l2 == null){
            return l1;
        }
        if(l1.val <= l2.val){
            l1.next = mergeTwoLists(l1.next,l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }
    }
}
24. 树的子结构
/**
 * 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) {
        boolean res = false;
        if(A != null && B != null){
            if(A.val == B.val){
                res = proveSubStructure(A,B);
            }
            if(res == false){
                res = isSubStructure(A.left,B);
            }
            if(res == false){
                res = isSubStructure(A.right,B);
            }
        }
        return res;
    }
    public boolean proveSubStructure(TreeNode A, TreeNode B){
        if(B == null){
            return true;
        }
        if(A == null){
            return false;
        }
        if(A.val != B.val){
            return false;
        }
        return proveSubStructure(A.left,B.left) && proveSubStructure(A.right,B.right);
    }
}
25. 二叉树的镜像
/**
 * 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;
        }
        if(root.left == null && root.right ==null){
            return root;
        }
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        if(root.left != null){
            mirrorTree(root.left);
        }
        if(root.right != null){
            mirrorTree(root.right);
        }
        return root;
    }
}
26. 对称的二叉树
/**
 * 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) {
        return isSym(root,root);
    }
    public boolean isSym(TreeNode rootA, TreeNode rootB){
        if(rootA == null && rootB == null){
            return true;
        }
        if(rootA == null || rootB == null){
            return false;
        }
        if(rootA.val != rootB.val){
            return false;
        }
        return isSym(rootA.left,rootB.right) && isSym(rootA.right,rootB.left);
    }
}
27. 顺时针打印矩阵
class Solution {
    int[] res;
    int index = 0;
    public int[] spiralOrder(int[][] matrix) {
        if(matrix == null || matrix.length <= 0 || matrix[0].length <= 0){
            return new int[]{};
        }
        int start = 0;
        int rows = matrix.length;
        int cols = matrix[0].length;
        res = new int[rows*cols];

        while(rows>start*2 && cols>start*2){
            spiralOrderToInt(matrix,cols,rows,start);
            start ++;
        }
        return res;
    }
    public void spiralOrderToInt(int[][] matrix,int cols,int rows,int start){
        int rowEnd = rows-1-start;
        int colEnd = cols-1-start;
        //1.从左往右打印一行
        for(int i=start; i<=colEnd; i++){
            res[index] = matrix[start][i];
            index ++;
        }
        //2.从上往下
        if(start < rowEnd){
            for(int i=start+1; i<=rowEnd; i++){
                res[index] = matrix[i][colEnd];
                index ++;
            }
        }
        //3.从右往左
        if(start<rowEnd && start<colEnd){
            for(int i=colEnd-1; i>=start; i--){
                res[index] = matrix[rowEnd][i];
                index ++;
            }
        }
        //4.从下往上
        if(start<colEnd && start+1<rowEnd){
            for(int i=rowEnd-1; i>=start+1; i--){
                res[index] = matrix[i][start];
                index ++;
            }
        }
    }
}
28. 包含min函数的栈
class MinStack {
    Stack<Integer> stack;
    Stack<Integer> stackAssit;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack();
        stackAssit = new Stack();
    }
    
    public void push(int x) {
        stack.push(x);
        if(stackAssit.empty() || stackAssit.peek() > x){
            stackAssit.push(x);
        } else {
            stackAssit.push(stackAssit.peek());
        }
    }
    
    public void pop() {
        if(!stack.empty() && !stackAssit.empty()){
            stack.pop();
            stackAssit.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int min() {
        return stackAssit.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();
 */
29. 栈的压入、弹出序列

参考:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/solution/mian-shi-ti-31-zhan-de-ya-ru-dan-chu-xu-lie-mo-n-2/

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(int num : pushed) {
            stack.push(num); // num 入栈
            while(!stack.isEmpty() && stack.peek() == popped[i]) { // 循环判断与出栈
                stack.pop();
                i++;
            }
        }
        return stack.isEmpty();
    }
}
30. 从上到下打印二叉树(1)
/**
 * 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[]{};
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        List<Integer> resArr = new ArrayList<Integer>();
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            resArr.add(node.val);
            if(node.left != null){
                queue.offer(node.left);
            }
            if(node.right != null){
                queue.offer(node.right);
            }
        }
        int[] res = new int[resArr.size()];
        for(int i=0; i<resArr.size(); i++){
            res[i] = resArr.get(i);
        }
        return res;
    }
}
31. 从上到下打印二叉树(2)
/**
 * 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){
            List<List<Integer>> list = new ArrayList<>();
            return list;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        List<Integer> listRow = new ArrayList<Integer>();
        List<List<Integer>> list = new ArrayList<>();
        int numNowLine = 1;
        int numAfterLine = 0;
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            listRow.add(node.val);
            numNowLine --;

            if(node.left != null){
                queue.offer(node.left);
                numAfterLine ++;
            }
            if(node.right != null){
                queue.offer(node.right);
                numAfterLine ++;
            }

            if(numNowLine == 0){
                list.add(listRow);
                listRow = new ArrayList<Integer>();
                numNowLine = numAfterLine;
                numAfterLine = 0;
            }
        }
        return list;
    }
}
32. 从上到下打印二叉树(3)之字形

用了两个栈来回的方法

/**
 * 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){
            List<List<Integer>> list = new ArrayList<>();
            return list;
        }
        Stack<TreeNode> stack1 = new Stack<TreeNode>();
        Stack<TreeNode> stack2 = new Stack<TreeNode>();
        List<List<Integer>> list = new ArrayList<>();
        stack1.push(root);
        //int lines = 1;

        while(!stack1.empty() || !stack2.empty()){
            List<Integer> listRow = new ArrayList<Integer>();
            TreeNode node;
            while(!stack1.empty()){
                node = stack1.pop();
                listRow.add(node.val);
                if(node.left != null){
                    stack2.push(node.left);
                }
                if(node.right != null){
                    stack2.push(node.right);
                }
            }
            if(listRow.size() > 0){
                list.add(listRow);
            }
            listRow = new ArrayList<Integer>();
            while(!stack2.empty()){
                node = stack2.pop();
                listRow.add(node.val);
                if(node.right != null){
                    stack1.push(node.right);
                }
                if(node.left != null){
                    stack1.push(node.left);
                }
            }
            if(listRow.size() > 0){
                list.add(listRow);
            }
        }
        return list;
    }
}
33. 二叉搜索树的后序遍历序列
class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return verifySub(postorder, 0, postorder.length-1);
    }
    public boolean verifySub(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 && verifySub(postorder, i, m - 1) && verifySub(postorder, m, j - 1);

    }
}
34. 二叉树中和为某一值的路径
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 /*
class Solution {
    List<List<Integer>> list = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        if(root == null){
            return list;
        }
        LinkedList<Integer> path = new LinkedList<Integer>();
        int currentSum = 0;
        findPath(root,sum,path,currentSum);
        return list;
        
    }
    public void findPath(TreeNode root, int sum, LinkedList<Integer> path, int currentSum){
        currentSum = currentSum+root.val;
        path.add(root.val);

        boolean isLeaf = root.left==null && root.right==null;
        if(currentSum==sum && isLeaf){
            list.add(path);
            path = new LinkedList<Integer>();
        }
        if(root.left != null){
            findPath(root.left,sum,path,currentSum);
        }
        if(root.right != null){
            findPath(root.right,sum,path,currentSum);
        }
        path.removeLast();
    }
}*/

class Solution {
    LinkedList<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> path = new LinkedList<>(); 
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root, sum);
        return res;
    }
    void recur(TreeNode root, int tar) {
        if(root == null) return;
        path.add(root.val);
        tar -= root.val;
        if(tar == 0 && root.left == null && root.right == null)
            res.add(new LinkedList(path));
        recur(root.left, tar);
        recur(root.right, tar);
        path.removeLast();
    }
}
35. 复杂链表的复制
/*
// 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;
    }
}
*/
/*
// 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;
        }
        copy(head);
        randomDirect(head);
        return reList(head);
    }
    //拷贝链表
    private void copy(Node head){
        while(head!=null){
            Node cloneNode = new Node(head.val);
            Node nextNode = head.next;
            head.next = cloneNode;
            cloneNode.next = nextNode;
            head = cloneNode.next;
        }
    }
    //指定随机指针
    private void randomDirect(Node head){
        while(head!=null){
            Node cloneNode = head.next;
            if(head.random!=null){
                Node direct = head.random;
                cloneNode.random = direct.next;
            }
            head = cloneNode.next;
        }
    }
    //重新连接 链表
    private Node reList(Node head){
        Node cloneNode = head.next;
        Node cloneHead = cloneNode;
        head.next = cloneNode.next;
        head = head.next;
        while(head!=null){
            cloneNode.next = head.next;
            head.next = head.next.next;
            head = head.next;
            cloneNode = cloneNode.next;
        }
        return cloneHead;
    }
}

36. 二叉搜索树与双向链表
/*
// 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指向双向链表中的尾节点
    }
}
37. 序列化/反序列化二叉树
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {
    public String serialize(TreeNode root) {
        if(root == null) return "[]";
        StringBuilder res = new StringBuilder("[");
        Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(node != null) {
                res.append(node.val + ",");
                queue.add(node.left);
                queue.add(node.right);
            }
            else res.append("null,");
        }
        res.deleteCharAt(res.length() - 1);
        res.append("]");
        return res.toString();
    }

    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> queue = new LinkedList<>() {{ add(root); }};
        int i = 1;
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(!vals[i].equals("null")) {
                node.left = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.left);
            }
            i++;
            if(!vals[i].equals("null")) {
                node.right = new TreeNode(Integer.parseInt(vals[i]));
                queue.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));
38. 字符串的排列
class Solution {
    //为了让递归函数添加结果方便,定义到函数之外,这样无需带到递归函数的参数列表中
    List<String> list = new ArrayList<>();
    //同;但是其赋值依赖c,定义声明分开
    char[] c;
    public String[] permutation(String s) {
        c = s.toCharArray();
        //从第一层开始递归
        dfs(0);
        //将字符串数组ArrayList转化为String类型数组
        return list.toArray(new String[list.size()]);
    }

    private void dfs(int x) {
        //当递归函数到达第三层,就返回,因为此时第二第三个位置已经发生了交换
        if (x == c.length - 1) {
            //将字符数组转换为字符串
            list.add(String.valueOf(c));
            return;
        }
        //为了防止同一层递归出现重复元素
        HashSet<Character> set = new HashSet<>();
        //这里就很巧妙了,第一层可以是a,b,c那么就有三种情况,这里i = x,正巧dfs(0),正好i = 0开始
        // 当第二层只有两种情况,dfs(1)i = 1开始
        for (int i = x; i < c.length; i++){
            //发生剪枝,当包含这个元素的时候,直接跳过
            if (set.contains(c[i])){
                continue;
            }
            set.add(c[i]);
            //交换元素,这里很是巧妙,当在第二层dfs(1),x = 1,那么i = 1或者 2, 不是交换1和1,要就是交换1和2
            swap(i,x);
            //进入下一层递归
            dfs(x + 1);
            //返回时交换回来,这样保证到达第1层的时候,一直都是abc。这里捋顺一下,开始一直都是abc,那么第一位置总共就3个交换
            //分别是a与a交换,这个就相当于 x = 0, i = 0;
            //     a与b交换            x = 0, i = 1;
            //     a与c交换            x = 0, i = 2;
            //就相当于上图中开始的三条路径
            //第一个元素固定后,每个引出两条路径,
            //     b与b交换            x = 1, i = 1;
            //     b与c交换            x = 1, i = 2;
            //所以,结合上图,在每条路径上标注上i的值,就会非常容易好理解了
            swap(i,x);
        }
    }

    private void swap(int i, int x) {
        char temp = c[i];
        c[i] = c[x];
        c[x] = temp;
    }
}
39. 数组中出现次数超过一半的数字
class Solution {
    public int majorityElement(int[] nums) {
        int cnt = 1;
        int element = nums[0];
        for(int i=1; i<nums.length; i++){
            if(cnt == 0){
                element = nums[i];
                cnt = 1;
            }
            else if(nums[i] == element){
                cnt ++;
            } else {
                cnt --;
            }
        }
        //还可以验证一下这个是不是大于一半多的数字

        return element;
    }
}
40. 最小的k个数
class Solution {
    /*
    //用快速选择排序来实现
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] res = new int[k];
        if(arr.length <= k){
            return arr;
        }
        if(k == 0){
            return res;
        }
        for(int i=0; i<k; i++){
            int minIndex = i;
            int min = arr[i];
            for(int j=i+1; j<arr.length; j++){
                if(min > arr[j]){
                    min = arr[j];
                    minIndex = j;
                }
                
            }
            if(minIndex != i){
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
        }
        
        for(int i=0; i<k; i++){
            res[i] = arr[i];
        }
        return res;
    }
    */
    //用一个队列来维护
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] vec = new int[k];
        if (k == 0) { // 排除 0 的情况
            return vec;
        }
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {
            public int compare(Integer num1, Integer num2) {
                return num2 - num1;
            }
        });
        for (int i = 0; i < k; ++i) {
            queue.offer(arr[i]);
        }
        for (int i = k; i < arr.length; ++i) {
            if (queue.peek() > arr[i]) {
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for (int i = 0; i < k; ++i) {
            vec[i] = queue.poll();
        }
        return vec;
    }

}
41. 数据流中的中位数

参考:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof/solution/mian-shi-ti-41-shu-ju-liu-zhong-de-zhong-wei-shu-y/

class MedianFinder {
    Queue<Integer> A, B;
    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() : (A.peek() + B.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();
 */
42. 连续子数组的最大和

动态规划

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        for(int i=1; i<nums.length; i++){
            if(nums[i-1] > 0){
                nums[i] = nums[i-1] +nums[i];
            }
            if(res < nums[i]){
                res = nums[i];
            }
        }
        return res;
    }
}
43. 1-n整数中1出现的次数

参考讲解:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/mian-shi-ti-43-1n-zheng-shu-zhong-1-chu-xian-de-2/

class Solution {
    public int countDigitOne(int n) {
        int res = 0;
        int cur = n%10;
        int high = n/10;
        int low = 0;
        int digit = 1;

        while(high!=0 || low!=n){
            if(cur == 0){
                res += high*digit;
            } else if(cur == 1){
                res += high*digit + low + 1;
            } else{
                res += (high+1)*digit;
            }
            low += cur*digit;
            cur = high%10;
            high = high/10;
            digit *= 10;

        }
        return res;
    }
}
44. 数字序列中某一位的数字
class Solution {
    public int findNthDigit(int n) {
        if(n == 0){
            return 0;
        }
        int digit = 1;
        long start = 1;
        long count = 9;
        while(n > count){
            n -= count;
            digit ++;
            start *= 10;
            count = 9*start*digit;
        }
        long num = start+(n-1)/digit;
        return Long.toString(num).charAt((n-1)%digit)-'0';
    }
}
45. 把数组排成最小的数
/*
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]);
        fastSort(strs, 0, strs.length - 1);
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }
    void fastSort(String[] strs, int l, int r) {
        if(l >= r) return;
        int i = l, j = r;
        String tmp = strs[i];
        while(i < j) {
            while((strs[j] + strs[l]).compareTo(strs[l] + strs[j]) >= 0 && i < j) j--;
            while((strs[i] + strs[l]).compareTo(strs[l] + strs[i]) <= 0 && i < j) i++;
            tmp = strs[i];
            strs[i] = strs[j];
            strs[j] = tmp;
        }
        strs[i] = strs[l];
        strs[l] = tmp;
        fastSort(strs, l, i - 1);
        fastSort(strs, i + 1, r);
    }
}
*/

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();
    }
}
46. 把数字翻译成字符串
class Solution {
    public int translateNum(int num) {
        String s = String.valueOf(num);
        int dp0 = 1;
        int dp1 = 1;
        int res = 0;
        for(int i=2; i<=s.length(); i++){
            String tmp = s.substring(i-2,i);
            if(tmp.compareTo("10")>=0 && tmp.compareTo("25")<=0){
                res = dp0 + dp1;
            } else{
                res = dp1;
            }
            dp0 = dp1;
            dp1 = res;
        }
        return dp1;
    }
}
47. 礼物的最大价值
class Solution {
    public int maxValue(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                int up = 0;
                int left = 0;
                if(i > 0){
                    up = dp[i-1][j];
                }
                if(j > 0){
                    left = dp[i][j-1];
                }
                dp[i][j] = Math.max(up,left) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }
}
48. 最长不含重复字符的子字符串
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++) {
            int i = dic.getOrDefault(s.charAt(j), -1); // 获取索引 i
            dic.put(s.charAt(j), j); // 更新哈希表
            tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
            res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
        }
        return res;
    }
}
49. 丑数
class Solution {
    public int nthUglyNumber(int n) {
        int[] dp = new int[n];
        dp[0] = 1;
        int a = 0, b = 0, c = 0;
        for(int i=1; i<n; i++){
            int n2=dp[a]*2, n3=dp[b]*3, n5=dp[c]*5;
            dp[i] = Math.min(Math.min(n2,n3),n5);
            while(dp[a]*2 <= dp[i]){
                a++;
            }
            while(dp[b]*3 <= dp[i]){
                b++;
            }
            while(dp[c]*5 <= dp[i]){
                c++;
            }
        }
        return dp[n-1];
    }
}
50. 第一个只出现一次的字符
/*写法一
class Solution {
    public char firstUniqChar(String s) {
        if(s.length() == 0 || s == null){
            return ' ';
        }
        char[] arrays = s.toCharArray();
        Map<Character,Boolean> map = new HashMap<>();
        for(char array: arrays){
            if(map.containsKey(array)){
                map.put(array,false);
            } else {
                map.put(array,true);
            }
        }
        for(char array: arrays){
            if(map.get(array)){
                return array;
            }
        }
        return ' ';
    }
}
*/
class Solution {
    public char firstUniqChar(String s) {
        HashMap<Character, Boolean> dic = new HashMap<>();
        char[] sc = s.toCharArray();
        for(char c : sc)
            dic.put(c, !dic.containsKey(c));
        for(char c : sc)
            if(dic.get(c)) return c;
        return ' ';
    }
}
51. 数组中的逆序对
//实际上就是 归并排序
/*有问题
class Solution {
    int sum = 0;
    public int reversePairs(int[] nums) {
        int[] temp = new int[nums.length];
        mergeSort(nums,0,nums.length-1,temp);
        return sum;
    }
    //分+合方法
    public void mergeSort(int[] arr, int left, int right, int[] temp){
        if(left < right){
            int mid = (left+right)/2; //中间索引
            //向左递归进行分解
            mergeSort(arr,left,mid,temp);
            //向右递归进行分解
            mergeSort(arr,mid+1,right,temp);
            //合并
            merge(arr,left,mid,right,temp);
        }
    }
    //合并的方法, 从后往前比
    public void merge(int[] arr, int left, int mid, int right, int[] temp){
        int i = mid; //初始化i,左边有序序列的初始索引
        int j = right; //初始化j,右边有序序列的初始索引
        int t = temp.length-1; //指向temp数组的当前索引

        //(一)
        //先把左右两边(有序)的数据按照规则填充到temp数组
        //直到左右两边的有序序列,有一边处理完毕为止
        while(i>=0 && j>mid){
            if(arr[i] >= arr[j]){
                temp[t] = arr[i];
                t --;
                i --;
                sum += j-mid;
            }else{
                temp[t] = arr[j];
                t --;
                j --;
               
            }
        }

        //(二)
        //把有剩余的一边的数据依次全部填充到temp
        while(i >=0){
            temp[t] = arr[i];
            t --;
            i --;
        }
        while(j > mid){
            temp[t] = arr[j];
            t --;
            j --;
        }

        //(三)
        //将temp数组的元素拷贝到arr
        t = 0;
        int tempLeft = left;
        while(tempLeft <= right){
            arr[tempLeft] = temp[t];
            t ++;
            tempLeft ++;
        }

    }
}
*/
//实际上就是 归并排序的思想
//照抄剑指offer代码
class Solution {
    public int reversePairs(int[] nums) {
        if(nums.length < 2){
            return 0;
        }
        int[] temp = new int[nums.length];
        for(int i=0; i<nums.length; i++){
            temp[i] = nums[i];
        }
        int sum = inversePairsCore(nums,temp,0,nums.length-1);
        return sum;
    }
    public int inversePairsCore(int[] nums, int[] temp, int start,int end){
        if(start == end){
            temp[start] = nums[start];
            return 0;
        }
        int length = (end - start)/2;
        int left = inversePairsCore(temp,nums,start,start+length);
        int right = inversePairsCore(temp,nums,start+length+1,end);

        int i = start+length;
        int j = end;
        int indexCopy = end;
        int count = 0;
        while(i >= start && j >= start+length+1){
            if(nums[i] > nums[j]){
                temp[indexCopy--] = nums[i--];
                count += j-start-length;
            }else{
                temp[indexCopy--] = nums[j--];
            }
        }
        for(;i>=start;--i){
            temp[indexCopy--]=nums[i];
        }
        for(;j>=start+length+1;--j){
            temp[indexCopy--]=nums[j];
        }
        return left+right+count;
    }
}
52. 两个链表的第一个公共节点

方法很多:双指针法、先求出两个链表的长度法、栈的方法、集合的方法

/**
 * 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) {
        if(headA == null || headB == null){
            return null;
        }
        int cntA = 0;
        int cntB = 0;
        ListNode tempA = headA;
        ListNode tempB = headB;
        while(tempA != null){
            cntA++;
            tempA = tempA.next;
        }
        while(tempB != null){
            cntB++;
            tempB = tempB.next;
        }
        tempA = headA;
        tempB = headB;
        if(cntA > cntB){
            for(int i=0; i<cntA-cntB; i++){
                tempA = tempA.next;
            }
        }
        if(cntA < cntB){
            for(int i=0; i<cntB-cntA; i++){
                tempB = tempB.next;
            }
        }
        while(tempA != null && tempB != null && tempA != tempB){
            tempA = tempA.next;
            tempB = tempB.next;
        }
        return tempA;
    }
    */
    //双指针法
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //tempA和tempB我们可以认为是A,B两个指针
        ListNode tempA = headA;
        ListNode tempB = headB;
        while (tempA != tempB) {
            //如果指针tempA不为空,tempA就往后移一步。
            //如果指针tempA为空,就让指针tempA指向headB(注意这里是headB不是tempB)
            tempA = tempA == null ? headB : tempA.next;
            //指针tempB同上
            tempB = tempB == null ? headA : tempB.next;
        }
        //tempA要么是空,要么是两链表的交点
        return tempA;
    }

}
53. 在排序数组中查找数字(1)

先找出右端点,再找出左端点

class Solution {
    public int search(int[] nums, int target) {
        int i = 0;
        int j = nums.length-1;
        int left = 0;
        int right = 0;
        while(i <= j){
            int mid = (i+j)/2;
            if(nums[mid] <= target){
                i = mid+1;
            }else{
                j = mid-1;
            }
        }
        right = i;
        // 若数组中无 target ,则提前返回
        if(j >= 0 && nums[j] != target) return 0;
        i = 0;
        while(i <= j){
            int mid = (i+j)/2;
            if(nums[mid] < target){
                i = mid+1;
            }else{
                j = mid-1;
            }
        }
        left = j;
        return right-left-1;
    }
}
54. 在排序数组中查找数字(2)
class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length-1;
        while(i <= j){
            int m = (i+j)/2;
            if(nums[m] == m){
                //注意这里的m==j和下面的m==0的边界条件
                if(m == j || nums[m+1] != (m+1)){
                    return m+1;
                }
                i = m+1;
            }else{
                if(m == 0 || nums[m-1] == (m-1)){
                    return m;
                }
                j = m-1;
            }
        }
        return i;
    }
}
55. 二叉搜索树的第k大节点
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 /*我的写法
class Solution {
    List<TreeNode> list = new ArrayList<TreeNode>();
    public int kthLargest(TreeNode root, int k) {
        mid(root);
        return list.get(k-1).val;
    }
    public void mid(TreeNode root){
        if(root == null){
            return;
        }
        mid(root.right);
        list.add(root);
        mid(root.left);
    }
}
*/
//大佬的写法,可以提前终止
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);
    }
}
56. 二叉树的深度
/**
 * 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;
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}
*/
//层序遍历
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        List<TreeNode> queue = new LinkedList<>() {{ add(root); }}, tmp;
        int res = 0;
        while(!queue.isEmpty()) {
            tmp = new LinkedList<>();
            for(TreeNode node : queue) {
                if(node.left != null) tmp.add(node.left);
                if(node.right != null) tmp.add(node.right);
            }
            queue = tmp;
            res++;
        }
        return res;
    }
}
57. 平衡二叉树
/**
 * 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) {
        return recur(root) != -1;
    }

    private int recur(TreeNode root) {
        if (root == null) return 0;
        int left = recur(root.left);
        if(left == -1) return -1;
        int right = recur(root.right);
        if(right == -1) return -1;
        return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
    }
}
58. 数组中数字出现的次数(1)
class Solution {
    public int[] singleNumbers(int[] nums) {
        int ret = 0;
        for (int n : nums) {
            ret ^= n;
        }
        int div = 1;
        while ((div & ret) == 0) {
            div <<= 1;
        }
        int a = 0, b = 0;
        for (int n : nums) {
            if ((div & n) != 0) {
                a ^= n;
            } else {
                b ^= n;
            }
        }
        return new int[]{a, b};
    }
}
59. 数组中数字出现的次数(2)
class Solution {
    public int singleNumber(int[] nums) {
        int[] counts = new int[32];
        for(int num : nums) {
            for(int j = 0; j < 32; j++) {
                counts[j] += num & 1;
                num >>>= 1;
            }
        }
        int res = 0, m = 3;
        for(int i = 0; i < 32; i++) {
            res <<= 1;
            res |= counts[31 - i] % m;
        }
        return res;
    }
}
60. 和为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];
    }
}
61. 和为s的连续正数序列
class Solution {
    public int[][] findContinuousSequence(int target) {
        List<int[]> vec = new ArrayList<int[]>();
        for (int l = 1, r = 2; l < r;) {
            int sum = (l + r) * (r - l + 1) / 2;
            if (sum == target) {
                int[] res = new int[r - l + 1];
                for (int i = l; i <= r; ++i) {
                    res[i - l] = i;
                }
                vec.add(res);
                l++;
            } else if (sum < target) {
                r++;
            } else {
                l++;
            }
        }
        return vec.toArray(new int[vec.size()][]);
    }
}
62. 翻转单词顺序
/*
//双指针法
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; // j 指向下个单词的尾字符
        }
        return res.toString().trim(); // 转化为字符串并返回
    }
}
*/
//Java内置函数
class Solution {
    public String reverseWords(String s) {
        String[] strs = s.trim().split(" "); // 删除首尾空格,分割字符串
        StringBuilder res = new StringBuilder();
        for(int i = strs.length - 1; i >= 0; i--) { // 倒序遍历单词列表
            if(strs[i].equals("")) continue; // 遇到空单词则跳过
            res.append(strs[i] + " "); // 将单词拼接至 StringBuilder
        }
        return res.toString().trim(); // 转化为字符串,删除尾部空格,并返回
    }
}
63. 左旋转字符串
/*
//字符串切片
class Solution {
    public String reverseLeftWords(String s, int n) {
        return s.substring(n, s.length()) + s.substring(0, n);
    }
}
*/
//遍历拼接
class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder res = new StringBuilder();
        for(int i = n; i < s.length(); i++)
            res.append(s.charAt(i));
        for(int i = 0; i < n; i++)
            res.append(s.charAt(i));
        return res.toString();
    }
}
64. 滑动窗口的最大值
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 j = 0, i = 1 - k; j < nums.length; i++, j++) {
            if(i > 0 && deque.peekFirst() == nums[i - 1])
                deque.removeFirst(); // 删除 deque 中对应的 nums[i-1]
            while(!deque.isEmpty() && deque.peekLast() < nums[j])
                deque.removeLast(); // 保持 deque 递减
            deque.addLast(nums[j]);
            if(i >= 0)
                res[i] = deque.peekFirst();  // 记录窗口最大值
        }
        return res;
    }
}
65. 队列的最大值
class MaxQueue {
    Queue<Integer> q;
    Deque<Integer> d;

    public MaxQueue() {
        q = new LinkedList<Integer>();
        d = new LinkedList<Integer>();
    }
    
    public int max_value() {
        if (d.isEmpty()) {
            return -1;
        }
        return d.peekFirst();
    }
    
    public void push_back(int value) {
        while (!d.isEmpty() && d.peekLast() < value) {
            d.pollLast();
        }
        d.offerLast(value);
        q.offer(value);
    }
    
    public int pop_front() {
        if (q.isEmpty()) {
            return -1;
        }
        int ans = q.poll();
        if (ans == d.peekFirst()) {
            d.pollFirst();
        }
        return ans;
    }
}

/**
 * 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();
 */
66. 扑克牌中的顺子
class Solution {
    public boolean isStraight(int[] nums) {
        Set<Integer> repeat = 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(repeat.contains(num)) return false; // 若有重复,提前返回 false
            repeat.add(num); // 添加此牌至 Set
        }
        return max - min < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
    }
}
67. 圆圈中最后剩下的数字
/*
//递归
class Solution {
    public int lastRemaining(int n, int m) {
        return f(n, m);
    }

    public int f(int n, int m) {
        if (n == 1) {
            return 0;
        }
        int x = f(n - 1, m);
        return (m + x) % n;
    }
}
*/
//迭代
class Solution {
    public int lastRemaining(int n, int m) {
        int f = 0;
        for (int i = 2; i != n + 1; ++i) {
            f = (m + f) % i;
        }
        return f;
    }
}
68. 股票的最大利润
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;
    }
}
69. 求1+2+。。。+n
class Solution {
    public int sumNums(int n) {
        boolean flag = n > 0 && (n += sumNums(n - 1)) > 0;
        return n;
    }
}
70. 不用加减乘除做加法
class Solution {
    public int add(int a, int b) {
        while(b != 0) { // 当进位为 0 时跳出
            int c = (a & b) << 1;  // c = 进位
            a ^= b; // a = 非进位和
            b = c; // b = 进位
        }
        return a;
    }
}
71. 构建乘积数组
class Solution {
    public int[] constructArr(int[] a) {
        if(a.length == 0) return new int[0];
        int[] b = new int[a.length];
        b[0] = 1;
        int tmp = 1;
        for(int i = 1; i < a.length; i++) {
            b[i] = b[i - 1] * a[i - 1];
        }
        for(int i = a.length - 2; i >= 0; i--) {
            tmp *= a[i + 1];
            b[i] *= tmp;
        }
        return b;
    }
}
72. 把字符串转换为整数
class Solution {
    public int strToInt(String str) {
        char[] c = str.trim().toCharArray();
        if(c.length == 0) return 0;
        int res = 0, bndry = Integer.MAX_VALUE / 10;
        int i = 1, sign = 1;
        if(c[0] == '-') sign = -1;
        else if(c[0] != '+') i = 0;
        for(int j = i; j < c.length; j++) {
            if(c[j] < '0' || c[j] > '9') break;
            if(res > bndry || res == bndry && c[j] > '7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (c[j] - '0');
        }
        return sign * res;
    }
}
73. 二叉搜索树的最近公共祖先
/**
 * 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) {
        while(root != null) {
            if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
                root = root.right; // 遍历至右子节点
            else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
                root = root.left; // 遍历至左子节点
            else break;
        }
        return root;
    }
}
74. 二叉树的最近公共祖先
/**
 * 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) return null; // 如果树为空,直接返回null
        if(root == p || root == q) return root; // 如果 p和q中有等于 root的,那么它们的最近公共祖先即为root(一个节点也可以是它自己的祖先)
        TreeNode left = lowestCommonAncestor(root.left, p, q); // 递归遍历左子树,只要在左子树中找到了p或q,则先找到谁就返回谁
        TreeNode right = lowestCommonAncestor(root.right, p, q); // 递归遍历右子树,只要在右子树中找到了p或q,则先找到谁就返回谁
        if(left == null) return right; // 如果在左子树中 p和 q都找不到,则 p和 q一定都在右子树中,右子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
        else if(right == null) return left; // 否则,如果 left不为空,在左子树中有找到节点(p或q),这时候要再判断一下右子树中的情况,如果在右子树中,p和q都找不到,则 p和q一定都在左子树中,左子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
        else return root; //否则,当 left和 right均不为空时,说明 p、q节点分别在 root异侧, 最近公共祖先即为 root
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值