leetcode刷题总结901-950

901. 股票价格跨度  

  描述:
    

 

 

   思路:单调栈。

    

class StockSpanner {
    Stack<Integer> prices, weights;

    public StockSpanner() {
        prices = new Stack();
        weights = new Stack();
    }

    public int next(int price) {
        int w = 1;
        while (!prices.isEmpty() && prices.peek() <= price) {
            prices.pop();
            w += weights.pop();
        }

        prices.push(price);
        weights.push(w);
        return w;
    }
}
View Code

904. 水果成篮

  描述:

    

 

 

   思路:问题可以看成  最长连续子序列。序列中最多包含两种元素。

907. 子数组的最小值之和

  描述:

    

 

 

   思路:

    

class Solution {
    public int sumSubarrayMins(int[] A) {
        int MOD = 1_000_000_007;

        Stack<RepInteger> stack = new Stack();
        int ans = 0, dot = 0;
        for (int j = 0; j < A.length; ++j) {
            // Add all answers for subarrays [i, j], i <= j
            int count = 1;
            while (!stack.isEmpty() && stack.peek().val >= A[j]) {
                RepInteger node = stack.pop();
                count += node.count;
                dot -= node.val * node.count;
            }
            stack.push(new RepInteger(A[j], count));
            dot += A[j] * count;
            ans += dot;
            ans %= MOD;
        }

        return ans;
    }
}

class RepInteger {
    int val, count;
    RepInteger(int v, int c) {
        val = v;
        count = c;
    }
}

 

910. 最小差值 II

  描述:
    

 

 

   思路:关键一点就是,在某一个节点,之前的数全部加K,之后的数全部减K

    

 

 

 915. 分割数组

  描述:

    

 

 

   思路:辅助数组存储左边最大的元素。

918. 环形子数组的最大和

  描述:

    

  思路:   

import java.util.Arrays;

public class Solution {

    public int maxSubarraySumCircular(int[] A) {
        int len = A.length;
        // 特例判断
        if (len == 0) {
            return 0;
        }
        if (len == 1) {
            return A[0];
        }

        int maxSubArray = maxSubArray(A);
        int minSubArrayExcludeHeadAndTail = minSubArray(A);

        int sum = 0;
        for (int value : A) {
            sum += value;
        }
        return Math.max(maxSubArray, sum - minSubArrayExcludeHeadAndTail);
    }

    public int maxSubArray(int[] nums) {
        int len = nums.length;
        // dp[i]:以 nums[i] 结尾的「连续」子区间的最大和
        int[] dp = new int[len];
        dp[0] = nums[0];

        for (int i = 1; i < len; i++) {
            if (dp[i - 1] >= 0) {
                dp[i] = dp[i - 1] + nums[i];
            } else {
                // dp[i - 1] < 0 的时候,前面的部分丢弃
                dp[i] = nums[i];
            }
        }

        // 全局扫一遍,找到最大值
        int res = dp[0];
        for (int i = 1; i < len; i++) {
            res = Math.max(res, dp[i]);
        }
        return res;
    }

    public int minSubArray(int[] nums) {
        // 思路和 maxSubArray 完全一致,求最大的地方改成最小
        // 但这里求的区间和不包括头和尾
        int len = nums.length;

        // dp[i]:以 nums[i] 结尾的「连续」子区间的最小和
        int[] dp = new int[len];
        dp[0] = nums[0];

        // 注意 i 的下标
        for (int i = 1; i < len - 1; i++) {
            if (dp[i - 1] >= 0) {
                // 加上前面的数,会使得结果更大,因此前面的部分丢弃
                dp[i] = nums[i];
            } else {
                dp[i] = dp[i - 1] + nums[i];
            }
        }

        // 全局扫一遍,找到最小值
        int res = dp[0];
        for (int i = 1; i < len; i++) {
            res = Math.min(res, dp[i]);
        }
        return res;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        // int[] A = {1, -2, 3, -2};
        // int[] A = {5, -3, 5};
        int[] A = {3, -1, 2, -1};
        int res = solution.maxSubarraySumCircular(A);
        System.out.println(res);
    }
}
View Code

    分两种情况,一种为没有跨越边界的情况,一种为跨越边界的情况

    没有跨越边界的情况直接求子数组的最大和即可;
    跨越边界的情况可以对数组求和再减去无环的子数组的最小和,即可得到跨越边界情况下的子数组最大和;

    

921. 使括号有效的最少添加

  描述:

    

 

 

   思路:栈

class Solution {
public:
    int minAddToMakeValid(string S) {
        stack<char> temp;
        for(int i=0;i<S.size();i++)
        {
            if(temp.empty())
            {
                temp.push(S[i]);
            }
            else{
                if(S[i]==')'&&temp.top()=='(')
                {
                    temp.pop();
                }
                else{
                    temp.push(S[i]);
                }
            }
        }
        return temp.size();
    }
};
View Code

923. 三数之和的多种可能

  描述:

    

 

 

   思路:可以通过hashmap  <num,count>完成。

    也可以通过动态规划。 dp[n][j][k]表示前n个数中某j个数的和为k的个数。

    首先,dp[i][j][k]表示考虑前i个数时,从中选出j个数,组成k大小的方案数。这里的定义是从01背包的定义拓展而来的,这里加入了一个约束限制,就是要从前i个数中选出j个数组成k大小。这样的好处是,如果选择最后一个数,则根据定义的最优子结构性质,可以很简单的使用dp[i - 1][j - 1][k - A[i]]来计算当前除去最后一个数的总共选法数;如果不选择最后一个数,则直接加上不选择的数量个数,即dp[i - 1][j][k]。

926. 将字符串翻转到单调递增

  描述:

    

 

 

   思路:

    dp[i][0],dp[i][1] 分别代表字符 S[i] 最终选择 0 和 1 的最少翻转次数,
    考虑到递增,那么 dp[i][0] 只能由 dp[i-1][0] 转化而来,所以,状态转移方程如下:

    如果 S[i] 是 '1':
    dp[i][0] = dp[i-1][0] + 1 # 只能从 0 转化来,翻转 '1' 为 '0',翻转次数加 1
    dp[i][1] = min(dp[i-1][0], dp[i-1][1]) # 已经为 '1',无需翻转

    如果 S[i] 是 '0':
    dp[i][0] = dp[i-1][0] # 只能从 0 转化来,无需翻转
    dp[i][1] = min(dp[i-1][0] + 1, dp[i-1][1] + 1) # 翻转 '0' 为 '1',翻转次数加 1

class Solution:
    def minFlipsMonoIncr(self, S: str) -> int:
        zero, one = 0, 0
        for c in S:
            if c == '1':
                one, zero = min(zero, one), zero + 1
            else:
                one = min(zero + 1, one + 1)
        return min(zero, one)
View Code

930. 和相同的二元子数组

  描述:

    

  思路:前缀和+hash.

931. 下降路径最小和

  描述;
    

 

   思路:动态规划,从底向上。

939. 最小面积矩形

  描述:

    

 

   思路:将所有点放入集合中,并枚举矩形对角线上的两个点,并判断另外两个点是否出现在集合中。例如我们在枚举到 (1, 1) 和 (5, 5) 时,我们需要判断 (1, 5) 和 (5, 1) 是否也出现在集合中。

945. 使数组唯一的最小增量

  描述:

    

 

   思路:

class Solution {
    public int minIncrementForUnique(int[] A) {
        // 先排序
        Arrays.sort(A);
        int move = 0;
        // 遍历数组,若当前元素小于等于它的前一个元素,则将其变为前一个数+1
        for (int i = 1; i < A.length; i++) {
            if (A[i] <= A[i - 1]) {
                int pre = A[i];
                A[i] = A[i - 1] + 1;
                move += A[i] - pre;
            }
        }
        return move;
    }
}
View Code

946. 验证栈序列

  描述;
    

 

   思路:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int N = pushed.length;
        Stack<Integer> stack = new Stack();

        int j = 0;
        for (int x: pushed) {
            stack.push(x);
            while (!stack.isEmpty() && j < N && stack.peek() == popped[j]) {
                stack.pop();
                j++;
            }
        }

        return j == N;
    }
}
View Code

948. 令牌放置

  描述:L    

    

 

   思路:如果让我们来玩令牌放置这个游戏,在让令牌正面朝上的时候,肯定要去找能量最小的令牌。同样的,在让令牌反面朝上的时候,肯定要去找能量最大的令牌。

class Solution {
    public int bagOfTokensScore(int[] tokens, int P) {
        Arrays.sort(tokens);
        int lo = 0, hi = tokens.length - 1;
        int points = 0, ans = 0;
        while (lo <= hi && (P >= tokens[lo] || points > 0)) {
            while (lo <= hi && P >= tokens[lo]) {
                P -= tokens[lo++];
                points++;
            }

            ans = Math.max(ans, points);
            if (lo <= hi && points > 0) {
                P += tokens[hi--];
                points--;
            }
        }

        return ans;
    }
}
View Code

 

posted @ 2020-07-20 12:37  _Meditation  阅读(327)  评论(0编辑  收藏  举报