算法打卡

46 阅读4分钟

算法思路

1750. 删除字符串两端相同字符后的最短长度思路:双指针加有一点点暴力的解答方式吧,就是贪心的往下减,用一个c来记录当前相同的这个字符如果往下不是两个相同的就看看有没有跟这个字符相同的,如果都没有了就跳出然后就右边减左边的长度即可,如果走到了循环的最末尾直接判断现在这个left跟我们的c是不是一样的如果是就是删完了如果不是就正常返回就行。

class Solution {
    public int minimumLength(String s) {
        int left = 0, right = s.length()-1;
        char c = ' ';
        while (left < right) {
            if (s.charAt(left) == s.charAt(right)) {
                c = s.charAt(left);
                right--;
                left++;
            }else if (s.charAt(right) == c) {
                right--;
            }else if (s.charAt(left) == c) {
                left++;
            } else if (s.charAt(right) != s.charAt(left)&&s.charAt(right) != c&&s.charAt(left) != c) {
                break;
            }
        }
        if (s.charAt(right)==c&&right==left){
            return 0;
        }
        return right - left+1;
    }
}

2210. 统计数组中峰和谷的数量思路:因为要找峰和谷,要比较两侧的大小如果有相同的不影响,那么首先想到的就是给两边相同的剔除出去就是去除相邻两边相同的元素,然后一次循环判断是否是峰或者是谷。

class Solution {
   public int countHillValley(int[] nums) {
        int ans = 0;
        // 使用Stream去重
        ArrayList<Integer> list = new ArrayList<>();
        if (nums.length > 0) {
            list.add(nums[0]);
            for (int i = 1; i < nums.length; i++) {
                if (nums[i] != nums[i - 1]) {
                    list.add(nums[i]);
                }
            }
        }
        // 转换回数组
        int[] uniqueArray = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            uniqueArray[i] = list.get(i);
        }
        for (int i = 1; i < uniqueArray.length - 1; i++) {
            int left = i - 1, right = i + 1;
            if (uniqueArray[left] < uniqueArray[i] && uniqueArray[right] < uniqueArray[i]) {
                ans++;
            } else if (uniqueArray[left] > uniqueArray[i] && uniqueArray[right] > uniqueArray[i]) {
                ans++;
            }
        }
        return ans;
    }
}

2105. 给植物浇水 II思路:双指针思路,一个左边浇水,一个右边浇水,然后同时进行往前进的速度相同,使用变量才存储两个水桶的剩余水量,如果小于需要的补水数加一即可,如果相同取最高的哪个高于需求的就不用加如果小于就补水数加一。

class Solution {
   public int minimumRefill(int[] plants, int capacityA, int capacityB) {
        int left = 0, right = plants.length - 1;
        int ans = 0;
        int currentA = capacityA, currentB = capacityB;
        while (left <= right) {
            if (left == right) {  // 只剩一株植物
                if (Math.max(currentA, currentB) < plants[left]) {
                    ans++;  // 必须补水
                }
                break;
            }
            // Alice浇左边的植物
            if (currentA < plants[left]) {
                currentA = capacityA;
                ans++;
            }
            currentA -= plants[left];
            left++;
            // Bob浇右边的植物
            if (currentB < plants[right]) {
                currentB = capacityB;
                ans++;
            }
            currentB -= plants[right];
            right--;
        }
        return ans;
    }
}

100578. 中位数之和的最大值周赛第一题思路:贪心求奇数和,因为只能要中位数,那么就是排序后,去第二大的数的和取过之后就往后走,然后一共取nums的长度除以3的个数个。

class Solution {
    public long maximumMedianSum(int[] nums) {
        long ans = 0;
        Arrays.sort(nums);
        int i = nums.length - 2;
        int count = nums.length/3;
        for (int j = 0; j < count; j++) {
            ans += nums[i];
            i-=2;
        }
        return ans;
    }
}

3628. 插入一个字母的最大子序列数思路:首先是动态规划的获取字符串中lct的个数,然后求到这个个数之后,这个就是基础的子序列的个数了,那么我们只需要求插入一个元素之后可以增加的个数,如果插入l只能是在最左边增加的个数就是字符串里面ct子序列的个数,如果是插入t的话就是字符串里面子序列lc的个数,都可以用跟求lct子序列个数一样的方式来求,如果是插入c就需要写一个方法来求,使用的循环求在每个位置中插入c前面的l个数后面的t个数然后相乘就是可以增加的个数然后求最大即可。然后注意字符串长度太大所以都要用long来记录。

class Solution {
     public long numOfSubsequences(String s) {
        long ans = 0;
        long lct = numDistinct(s, "LCT");
        long lc = numDistinct(s, "LC");
        long ct = numDistinct(s, "CT");
        long t = 0, l = 0;
        for (long i = 0; i < s.length(); i++) {
            if (s.charAt((int) i) == 'T') {
                t++;
            }
        }
        long lt = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == 'T') {
                t--;
            } else if (s.charAt(i) == 'L') {
                l++;
            }
            lt = Math.max(lt, l * t);
        }
        return Math.max(lct+lc,Math.max(lct+ct,lct+lt));
    }
    //求一个字符串里面另一个字符串的个数
    /**
     * 两个字符串,使用s来进行外层循环
     * 然后t来进行内部循环dp[j]就是走完一个t的循环然后判断当前这个s的位置中前面有几个相同的字母
     * 就是根据两次循环 内层循环用来找这个位置之前出现过的子序列字母的个数 如果都出现了就会给结果加上
     * 就是使用循环来判断这个给出的子序列在当前s的位置中子序列的字母出现过的次数,如果全都大于1说明就是有子序列的
     * 然后相加最后的dp[n]就是这个子序列的长度
     *
     * @param s
     * @param t
     * @return
     */
    public static long numDistinct(String s, String t) {
        long m = s.length(), n = t.length();
        long[] dp = new long[(int) (n + 1)];
        dp[0] = 1; // 空串是任何字符串的子序列

        for (long i = 1; i <= m; i++) {
            long prev = dp[0]; // 保存 dp[i-1][j-1] 的初始值
            for (long j = 1; j <= n; j++) {
                long temp = dp[(int) j]; // 保存当前 dp[j] 的值
                if (s.charAt((int) (i - 1)) == t.charAt((int) (j - 1))) {
                    dp[(int) j] += prev; // dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
                }
                prev = temp; // 更新 prev 为 dp[i-1][j-1]
            }
        }
        return dp[(int) n];
    }
}