LeetCode之最值问题系列问题求解

最值系列题目求解

这类型题目的特点就是一个数组,或者字符串, 给的条件是连续或者不连续,或者给定限定条件进行求解的情况

解题的关键

  1. 采用两个变量
    • 一个变量记录前面的条件,或者最后一个不满足题意的index,或者最小值, 比如股票题目当中j ,或者最大不重复字符串
    • 一个变量代表截止到处理到该位置处的最大结果值
  2. 动态规划保存前面的计算结果,全局变量保存计算结果

利益最大买卖股票

只能进行一次买卖的基本情况

class Solution {
    public int maxProfit(int[] prices) {
        // 动态规划问题
        if(prices==null||prices.length<2)
            return 0;
        int max = 0;
      //  int i = 0;
        int j = prices[0];
        for(int i=1;i<prices.length;i++){
            //有一个基准
            // 最小值更新, 记录最小的买入位置
            j = Math.min(j,prices[i]);
         max =Math.max(prices[i]-j,max);
        }
        return max;
    }
}

最长递增子序列

可以间隔处理
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

解法一:动态规划

时间复杂度为O(N*N)

class Solution {
    public int lengthOfLIS(int[] nums) {
       int n = nums.length;
        if(n==0) return 0;
        if(n==1) return 1;
        int max = 1;
        int [] dp =new int[n];
        Arrays.fill(dp,1);
        dp[0] =1;
        for(int i=1;i<n;++i){
            for(int j=i-1;j>=0;--j)
            {
                if(nums[j]<nums[i])
                {
                    //因为要求一个增长序列,u=
                   // 状态转移方程dp[i]在前面选择一个num[j]<nums[i],总多条件中选择一个·满足题意的max 的j,然后加i
                    dp[i] = Math.max(dp[j]+1,dp[i]);
                }
                //如果一个元素找不到一个比他任何一个比他小的元素,那么以这个元素为nums[i] 为尾巴的增长序列只能为1,自己本身
                }
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

解法二:有序二叉查找插入

B[] 维护连续数组的情况,就是有序的情况, A[] 代表处理的元素, 就是讲i 插入到B[]合适的位置里面去,

  • 如果A[i]>B[end] , B[++end]=A[i],
  • 要不然就是要查找插入位置
class Solution {
    public int lengthOfLIS(int[] A) {
       
        if(A==null||A.length==0)
            return 0;
  
        int length = A.length;
        int[] B = new int[length];
        B[0] = A[0];
        int end = 0;
        for (int i = 1; i < length; ++i) {
            // 如果当前数比B中最后一个数还大,直接添加
            if (A[i] > B[end]) { B[++end] = A[i]; continue;
            }
            // 否则,需要先找到替换位置
        int pos = findInsertPos(B, A[i], 0, end);
        B[pos] = A[i];
        }
        return end+ 1;
    }

    private int findInsertPos(int[] B, int n, int start, int end) {
        while (start < end) {
            int mid = start + (end - start) / 2;// 直接使用(high + low) / 2 可能导致溢出
            if (B[mid] < n) {
                start = mid + 1;
            } else if (B[mid] > n) {
                end = mid ;
            } else {
                return mid;
            }
        }
        return start;
    }
}

最大子序列和

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

要求连续的情况

public int maxSubArray(int[] A) {
        int n = A.length;
        int[] dp = new int[n];//dp[i] means the maximum subarray ending with A[i];
        dp[0] = A[0];
        int max = dp[0];
        for(int i = 1; i < n; i++){
            dp[i] = A[i] + (dp[i - 1] > 0 ? dp[i - 1] : 0);
            max = Math.max(max, dp[i]);
        } 
        return max;
}

最长不重复字符串

HashMap

HashMap 记录每个出现过字符的<char, 最后的index>

其中我们让j 记录最后一个不重复的字符

abcabc

当i =3的时候,处理 j指向第一个b的位置, a bca 不重复的情况

分为两次

public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        int max=0;
        for (int i=0, j=0; i<s.length(); ++i){
        //已经出现过的情况,j代表最后一个导致不满足不重复的位置+1
        //比如 absceffdasfa 那当处理到 第二个a的时候,那么
            if (map.containsKey(s.charAt(i))){
           // 因为可能有多个元素重复,因此 不重复元素最起码的位置是s.charAt(i)+ 1,这个z
                j = Math.max(j,map.get(s.charAt(i))+1);
            }
            map.put(s.charAt(i),i);
            max = Math.max(max,i-j+1);
        }
        return max;
    }

动态规划

逐步高新最后一个不满足最长连续子字符串的长度


//SWWKPE   像这种情况就是index 当处理到P  j 最多向前处理到第二个index, 第一个w我们就不处理了,因为一定重复了,这种情况,

// wwkeflalecm  同样在处理这种情况时我们是不需要j 遍历到第一个e的, index 等于 第一个e 后迈进的f 
class Solution {
    public int lengthOfLongestSubstring(String s) {
    // 动态规划问题 规划来解决
            if(s==null||s.length()==0)
            	return 0;
            int len = s.length();
           int max = 0;
        if(len==1)
            return 1;
        int index =0;
        for(int i=1;i<len;i++){
             int j=i-1; 
             // char[i]==char[j],在不重复里面i和j之间我们只需要保存一个元素即可,保留我们char[i] 比如 abca 我们最终j 是0, i是3, 当时我们只要保持 bca , j++ =1, 3-1+1= 3 
             while(j>=index && s.charAt(i)!=s.charAt(j)){
                 j--;
             }
             // 最后一个不满足位置为啥是
             ++j;
             index =j;
             max = Math.max(i-j+1,max);
         }
        return max;
        }
   }

最长最多K个无重复字符的字符串长度

Given a string, find the length of the longest substring T that contains at most k distinct characters.

For example, Given s = “eceba” and k = 2,

T is “ece” which its length is 3.

解法一:快慢指针 + HashMap

一般这种题目都是采用一个快慢 pointer来做

  • 慢指针指向第一个起始位置 ,现在要决定的是什么时候更新慢指针pre

  • 快指针指向当前的处理位置 i

当前的可能长度就是i - pre + 1的长度情况

思考为何要使用while 循环包裹在外面的情况

代码

  • 这里里面的index 其实就是最长不重复字符里面的pre元素情况,
public class longest {
    public int solution(String s, int  k){
        if(s==null ||k<1)
            return 0;
        if(s.length()<k)
            return s.length();
        Map<Character, Integer> map =new HashMap<>();
        int pre =0;
        int result =k;
        for(int i=0;i<s.length();i++){
			//比如当前的处理元素是b,         map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1);
           处理到当前合适位置的情况吧,情况 eceb   处理成为 eb 满足k=2; 
            while(map.size()>k){
                char p =s.charAt(pre++);
                int count = map.get(p);
                count--;
                if(count==0)
                {
                    map.remove(p);
                }
                else
                {
                    map.put(p,count);
                }
            }
			result =Math.max(result,i-pre+1);
        }
        return result;
      }
    public static void main(String[] args) {
        longest test =new longest();
        System.out.println(test.solution("ececbac",2));
    }
}

处理流程

在处理 ece 之前不用进行while(map.size()>k)这段代码的处理流程情况,

eceb 第一次while处理 后变成 ceb, 然后进入第二次处理流程的情况

eb 处理成为这样情况 最后 pre 变成了 2, 3-2+1 最大的长度为2 所以还是不满足该种情况

p

解法二: 快慢指针

public class Solution {
    public int lengthOfLongestSubstringKDistinct(String s, int k) {
        if (s == null || s.length() == 0 || k <= 0) {
            return 0;
        }
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        int count = 0;
        int start = 0;
        int max = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (map.containsKey(c)) {
                map.put(c, map.get(c) + 1);
            } else {
                map.put(c, 1);
                // 如果是第一次put的有可能
                while (map.size() > k) {
                    char rm = s.charAt(start);
                    int tempCount = map.get(rm);
                    if (tempCount > 1) {
                        map.put(rm, tempCount - 1);
                    } else {
                        map.remove(rm);
                    }
                    start++;
                   //
                    count--;
                }
            }
            count++;
            max = Math.max(max, count);
        }
        return max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值