牛客Leetcode高频题解(下)

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

java 复制代码
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;
}

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

java 复制代码
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;
}

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

最多可以买入卖出2次,那实际上相当于它的状态多了几个,对于每天有到此为止的最大收益和持股情况两个状态,持股情况有了5种变化,我们用:

dpi0表示到第i天为止没有买过股票的最大收益

dpi1表示到第i天为止买过一次股票还没有卖出的最大收益

dpi2表示到第i天为止买过一次也卖出过一次股票的最大收益

dpi3表示到第i天为止买过两次只卖出过一次股票的最大收益

dpi4表示到第i天为止买过两次同时也买出过两次股票的最大收益

java 复制代码
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])); 
    }
}

分糖果问题

java 复制代码
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;
}

主持人调度(二)

java 复制代码
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;
    }
}

矩阵的最小路径和

java 复制代码
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];
}

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

java 复制代码
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()];
    }
}

兑换零钱(一)

java 复制代码
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];
    }
}

最长公共子序列(二)

java 复制代码
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--;
            }
        }
    }
}

二分查找-I

java 复制代码
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)从左下角找

java 复制代码
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;
}

(2)从右上角找

java 复制代码
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;
}

寻找峰值

java 复制代码
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; 
}

数组中的逆序对

java 复制代码
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);
    }
}

旋转数组

java 复制代码
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)二分法

java 复制代码
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];
}

(2)遍历查找

java 复制代码
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;
}

比较版本号

java 复制代码
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;
}

螺旋矩阵

java 复制代码
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) 矩阵转置

java 复制代码
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;
    }
}

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

java 复制代码
 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;
}
相关推荐
fangzhanpeng1683 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心6 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552712 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552712 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝13 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552714 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552714 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552716 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552717 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552718 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节