• 牛客Leetcode高频题解(下)


    买卖股票的最好时机(一)

    public int maxProfit (int[] prices) {
        int min = prices[0];
        int max = 0;
        for(int i=0;i<prices.length;i++){
            min=Math.min(prices[i],min);
            max=Math.max(max,prices[i]-min);
        }
        return max;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    买卖股票的最好时机(二)

    public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 2)
            return 0;
        int length = prices.length;
        //初始条件
        int hold = -prices[0];  //持有股票
        int noHold = 0;         //没持股票
        for (int i = 1; i < length; i++) {
            //递推公式转化的
            noHold = Math.max(noHold, hold + prices[i]);
            hold = Math.max(hold, noHold - prices[i]);
        }
        //最后一天肯定是手里没有股票的时候利润才会最大,
        //所以这里返回的是noHold
        return noHold;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    买卖股票的最好时机(三)

    最多可以买入卖出2次,那实际上相当于它的状态多了几个,对于每天有到此为止的最大收益和持股情况两个状态,持股情况有了5种变化,我们用:
    dp[i][0]表示到第i天为止没有买过股票的最大收益
    dp[i][1]表示到第i天为止买过一次股票还没有卖出的最大收益
    dp[i][2]表示到第i天为止买过一次也卖出过一次股票的最大收益
    dp[i][3]表示到第i天为止买过两次只卖出过一次股票的最大收益
    dp[i][4]表示到第i天为止买过两次同时也买出过两次股票的最大收益

    import java.util.*;
    public class Solution {
        public int maxProfit (int[] prices) {
            int n = prices.length;
            int[][] dp = new int[n][5];
            //初始化dp为最小
            Arrays.fill(dp[0], -10000); 
            //第0天不持有状态
            dp[0][0] = 0; 
            //第0天持有股票
            dp[0][1] = -prices[0]; 
            //状态转移
            for(int i = 1; i < n; i++){ 
                dp[i][0] = dp[i - 1][0]; 
                dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
                dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
                dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
                dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
            }
            //选取最大值,可以只操作一次
            return Math.max(dp[n - 1][2],Math.max(0, dp[n - 1][4])); 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    分糖果问题

    public int candy (int[] arr) {
        int n=arr.length;
        if(n<=1)
            return n;
        int[] nums = new int[n];
        //初始化
        for(int i = 0; i < n; i++)
            nums[i] = 1;
        //从左到右遍历
        for(int i = 1; i < arr.length; i++){ 
            //如果右边在递增,每次增加一个
            if(arr[i] > arr[i - 1]) 
                nums[i] = nums[i - 1] + 1; 
        }
        //记录总糖果数
        int res = nums[arr.length - 1]; 
        //从右到左遍历
        for(int i = arr.length - 2; i >= 0; i--){ 
             //如果左边更大但是糖果数更小
            if(arr[i] > arr[i + 1] && nums[i] <= nums[i + 1])
                nums[i] = nums[i + 1] + 1; 
            //累加和
            res += nums[i]; 
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    主持人调度(二)

    import java.util.*;
    public class Solution {
        public int minmumNumberOfHost (int n, int[][] startEnd) {
            int[] start = new int[n];
            int[] end = new int[n];
            //分别得到活动起始时间
            for(int i = 0; i < n; i++){
                start[i] = startEnd[i][0];
                end[i] = startEnd[i][1];
            }
            //单独排序
            Arrays.sort(start, 0, start.length);
            Arrays.sort(end, 0, end.length);
            int res = 0;
            int j = 0;
            for(int i = 0; i < n; i++){
                //新开始的节目大于上一轮结束的时间,主持人不变
                if(start[i] >= end[j]) 
                    j++;  
                else
                    //主持人增加
                    res++;  
            }
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    矩阵的最小路径和

    public int minPathSum (int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int dp[][] = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i == 0 && j == 0) {
                    dp[0][0] = matrix[0][0];
                } else if (i == 0) {
                    //第一行只能从左边走过来
                    dp[i][j] = matrix[i][j] + dp[i][j - 1];
                } else if (j == 0) {
                    //第一列只能从上面走下来
                    dp[i][j] = matrix[i][j] + dp[i - 1][j];
                } else {
                    //递推公式,取从上面走下来和从左边走过来的最小值+当前坐标的值
                    dp[i][j] = matrix[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[m - 1][n - 1];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    把数字翻译成字符串(二)

    import java.util.*;
    public class Solution {
        public int solve (String nums) {
            //排除0
            if (nums.equals("0"))
                return 0;
            //排除只有一种可能的10 和 20
            if (nums == "10" || nums == "20")
                return 1;
           
            //当0的前面不是1或2时,无法译码,0种
            for (int i = 1; i < nums.length(); i++) {
                if (nums.charAt(i) == '0')
                    if (nums.charAt(i - 1) != '1' && nums.charAt(i - 1) != '2')
                        return 0;
            }
            
            int[] dp = new int[nums.length() + 1];
            //辅助数组初始化为1
            Arrays.fill(dp, 1);
            for (int i = 2; i <= nums.length(); i++) {
                //在11-19,21-26之间的情况
                if ((nums.charAt(i - 2) == '1' && nums.charAt(i - 1) != '0') ||
                        (nums.charAt(i - 2) == '2' && nums.charAt(i - 1) > '0' && nums.charAt(i - 1) < '7'))
                    dp[i] = dp[i - 1] + dp[i - 2];
                else
                    dp[i] = dp[i - 1];
            }
            return dp[nums.length()];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    兑换零钱(一)

    import java.util.*;
    public class Solution {
        public int minMoney (int[] arr, int aim) {
            //小于1的都返回0
            if (aim < 1)  return 0;
            
            int[] dp = new int[aim + 1];
            //dp[i]表示凑齐i元最少需要多少货币数
            Arrays.fill(dp, aim + 1);
            dp[0] = 0;
           
            //遍历1-aim元
            for (int i = 1; i <= aim; i++) {
                //每种面值的货币都要枚举
                for (int j = 0; j < arr.length; j++) {
                    //如果面值不超过要凑的钱才能用
                    if (arr[j] <= i)
                        //维护最小值
                        dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
                }
            }
            //如果最终答案大于aim代表无解
            return dp[aim] > aim ? -1 : dp[aim];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    最长公共子序列(二)

    public static String LCS(String s1, String s2) {
        int row = s1.length();
        int column = s2.length();
        // `dp[i][j]`表示从左到右,当处理到s1的第i个元素和s2的第j个元素时的公共子序列长度
        // 默认初始化为0,因此base case的 i == 0 和 j == 0 的情况不需要手动初始化
        int[][] dp = new int[row + 1][column + 1];
        // 状态转移
        for (int i = 1; i < row + 1; i++) {
            for (int j = 1; j < column + 1; j++) {
                // 字符相等,则通过前一个状态+1获得当前状态
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    // 字符不相等,则通过两个前面的情况的最大值获得当前最大公共子序列长度
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
       
        //目前dp记录了s1和s2的最长子序列的长度
        if (dp[row][column] == 0) 
            return "-1";
       
        // lcs用来储存结果数组
        char[] lcs = new char[dp[row][column]];
        // 因为要对dp倒着查看,所以lcs也倒着插入,cur表示当前插入的位置
        int cur = lcs.length - 1;
        // 通过双指针,遍历s1和s2字符串
        while (true) {
            // 相等则添加结果,两个指针左移
            if (s1.charAt(row - 1) == s2.charAt(column - 1)) {
                //记录字符
                lcs[cur--] = s1.charAt(row - 1);
                if (cur < 0) {
                    return new String(lcs);
                }
                row--;
                column--;
            } else {
                // 不相等,则根据dp保存的状态,进行指针移动
                if (dp[row - 1][column] > dp[row][column - 1]) {
                    // 忽略掉s1[row-1]
                    row--;
                } else {
                    // 忽略掉s2[column-1]
                    column--;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    二分查找-I

    public int search (int[] nums, int target) {
        int l = 0;
        int r = nums.length - 1;
        //从数组首尾开始,直到二者相遇
        while(l <= r){ 
            //每次检查中点的值
            int m = (l + r) / 2; 
            if(nums[m] == target)
                return m;
            //进入左的区间
            if(nums[m] > target) 
                r = m - 1;
            //进入右区间
            else 
                l = m + 1;
        }
        //未找到
        return -1; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    二维数组中的查找

    (1)从左下角找

    public boolean Find(int target, int [][] array) {
        int rows = array.length;
        if(rows == 0){
            return false;
        }
        int cols = array[0].length;
        if(cols == 0){
            return false;
        }
        // 左下
        int row = rows-1;
        int col = 0;
        while(row>=0 && col<cols){
            if(array[row][col] < target){
                col++;
            }else if(array[row][col] > target){
                row--;
            }else{
                return true;
            }
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    (2)从右上角找

    public boolean Find(int target, int [][] array) {
        int rows = array.length;
        if(rows == 0){
            return false;
        }
        int cols = array[0].length;
        if(cols == 0){
            return false;
        }
        // 右上
        int row = 0;   //注意
        int col = cols-1;    //注意
        while(row<rows && col>=0){    //注意
            if(array[row][col] < target){
                row++;        //注意
            }else if(array[row][col] > target){
                col--;      //注意
            }else{
                return true;
            }
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    寻找峰值

    public int findPeakElement (int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        //二分法
        while(left < right){ 
            int mid = (left + right) / 2;
            //右边是往下,不一定有坡峰
            if(nums[mid] > nums[mid + 1])
                right = mid;
            //右边是往上,一定能找到波峰
            else
                left = mid + 1;
        }
        return right; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    数组中的逆序对

    public class Solution {
        public int mod = 1000000007;
        public int mergeSort(int left, int right, int [] data, int [] temp){
            //停止划分
            if(left >= right)    
                return 0;
            //取中间
            int mid = (left + right) / 2; 
            //左右划分合并
            int res = mergeSort(left, mid, data, temp) + mergeSort(mid + 1, right, data, temp); 
            //防止溢出
            res %= mod;  
            int i = left, j = mid + 1;
            for(int k = left; k <= right; k++)
                temp[k] = data[k];
            for(int k = left; k <= right; k++){
                if(i == mid + 1)
                    data[k] = temp[j++];
                else if(j == right + 1 || temp[i] <= temp[j])
                    data[k] = temp[i++];
                //左边比右边大,答案增加
                else{ 
                    data[k] = temp[j++];
                    // 统计逆序对
                    res += mid - i + 1; 
                }
            }
            return res % mod;
        }
        
        public int InversePairs(int [] array) {
            int n = array.length;
            int[] res = new int[n];
            return mergeSort(0, n - 1, array, res);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    旋转数组

    public class Solution {
        public int[] solve (int n, int m, int[] a) {
            //取余,因为每次长度为n的旋转数组相当于没有变化
            m = m % n; 
            //第一次逆转全部数组元素
            reverse(a, 0, n - 1); 
            //第二次只逆转开头m个
            reverse(a, 0, m - 1); 
            //第三次只逆转结尾m个
            reverse(a, m, n - 1); 
            return a;
        }
        //反转函数
        public void reverse(int[] nums, int start, int end){ 
            while(start < end){
                swap(nums, start++, end--);
            }
        }
        //交换函数
        public void swap(int[] nums, int a, int b){ 
            int temp = nums[a];
            nums[a] = nums[b];
            nums[b] = temp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    旋转数组的最小数字

    (1)二分法

    public int minNumberInRotateArray(int [] array) {
        int left = 0;
        int right = array.length - 1;
        while(left < right){
            int mid = (left + right) / 2;
            //最小的数字在mid右边
            if(array[mid] > array[right])
                left = mid + 1;
            //无法判断,一个一个试
            else if(array[mid] == array[right])
                right--;
            //最小数字要么是mid要么在mid左边
            else
                right = mid;
        }
        return array[left];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    (2)遍历查找

    public int minNumberInRotateArray(int [] array) {
        //数组一定有元素
        int res = array[0]; 
        //遍历数组
        for(int i = 1; i < array.length; i++) {
            //每次维护最小值
            res = Math.min(res, array[i]); 
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    比较版本号

    public int compare(String version1, String version2) {
        String s1[] = version1.split("\\.");
        String s2[] = version2.split("\\.");
    
        int n1 = s1.length;
        int n2 = s2.length;
        int n = Math.max(n1, n2);
        int k1[] = new int[n];
        for (int i = 0; i < s1.length; i++) {
            k1[i] = Integer.valueOf(s1[i]);
        }
    
        int k2[] = new int[n];
        for (int i = 0; i < s2.length; i++) {
            k2[i] = Integer.valueOf(s2[i]);
        }
    
        for (int i = 0; i < n; i++) {
            if (k1[i] > k2[i]) {
                return 1;
            } else if (k1[i] < k2[i]) {
                return -1;
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    螺旋矩阵

    public ArrayList<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> list = new ArrayList<>();
    
        if(matrix.length == 0) {
            return list;
        }
    
        int left = 0; 
        int right = matrix[0].length - 1;
        int top = 0;
        int bottom = matrix.length - 1; 
        int x = 0;
    
    
        while(true) {
            for(int i = left; i <= right; i++) {  //从左到右
               list.add(matrix[top][i]) ; 
            }
    
            if(++top > bottom){
                break;
            } 
            for(int i = top; i <= bottom; i++){
                 list.add( matrix[i][right]);    //从上到下
            } 
    
            if(left > --right){
                break;
            } 
            for(int i = right; i >= left; i--){
                  list.add(matrix[bottom][i]); //从右到左
            } 
    
            if(top > --bottom){
                break;
            }
            for(int i = bottom; i >= top; i--){
                 list.add(matrix[i][left]);   //从下到上
            } 
    
            if(++left > right){
               break;
            } 
        }
        return list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    顺时针旋转矩阵

    (1) 矩阵转置

    import java.util.*;
    public class Solution {
        public int[][] rotateMatrix(int[][] mat, int n) {
            int length = mat.length;
            //矩阵转置
            for(int i = 0; i < length; ++i){
                for(int j = 0; j < i; ++j){
                    //交换上三角与下三角对应的元素
                    int temp = mat[i][j];
                    mat[i][j] = mat[j][i];
                    mat[j][i] = temp;
                }
            }
            //每行翻转
            for (int i = 0; i < length; i++) {
                for (int j = 0; j < length/2; j++){
                    int temp = mat[i][j];
                    mat[i][j] = mat[i][length - j - 1];
                    mat[i][length - j - 1] = temp;
                }
            }
            return mat;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (2)先上下交换,在对角线交换

     public int[][] rotateMatrix(int[][] matrix, int n) {
        int length = matrix.length;
        //先上下交换
        for (int i = 0; i < length / 2; i++) {
            int temp[] = matrix[i];
            matrix[i] = matrix[length - i - 1];
            matrix[length - i - 1] = temp;
        }
        //在按照对角线交换
        for (int i = 0; i < length; ++i) {
            for (int j = i + 1; j < length; ++j) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        return matrix;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    面试常问的dubbo的spi机制到底是什么?
    idea设置某个文件修改后所在父文件夹变蓝色
    自定义ListView下拉刷新上拉加载更多
    JavaWeb---- (1)互联网通信流程(超详细)
    什么是JavaScript中的闭包?
    常用通讯电平转换电路整理
    Java ElasticSearch-Linux面试题
    如何解决iOS打包工具AppUploader登录权限问题?
    基于图数据库的元数据血缘关系分析技术研究与实践
    【C语言】万字详讲操作符
  • 原文地址:https://blog.csdn.net/feiyanaffection/article/details/134007596