Seeker的奇妙求职冒险(杰杰的字节笔试)

替换后的最长重复字符

力扣原题424:https://leetcode-cn.com/problems/longest-repeating-character-replacement/
题目大意:
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

输入:
s = “ABAB”, k = 2

输出: 4

解释: 用两个’A’替换为两个’B’,反之亦然。
输入: s = “AABABBA”, k = 1

输出: 4

解释: 将中间的一个’A’替换为’B’,字符串变为 “AABBBBA”。 子串 “BBBB” 有最长重复字母, 答案为 4。

分析:
这道题看着吓人,其实是一道滑动窗口的题目。
首先计算出滑动窗口内的出现次数最多的元素个数max
然后计算出滑动窗口的大小right - left+1
二者相减,如果res <= k则说明可以通过替换元素使得这个字符串全部都是重复元素,并且移动right
否则同时移动leftright

//这是参考了力扣里面大神的代码写的
//我自己的写法只打败了40%的人,运行8ms,
//这个代码击败98%的人,运行时间4ms
class Solution {
    public int characterReplacement(String s, int k) {
        if(s == null || s.length() == 0)
            return 0;
        int[] map = new int[26];
        int maxCount = 0;
        int left = 0 ,right = 0;
        int res = 0;
        char[] str = s.toCharArray();
        while(right < s.length()){
        	//计算不重复子序列的长度
        	//这边其实代码不太规范
        	//最好不要在一行代码中进行多个变量的加减操作
        	//这里先获取了str[right]的值,
        	//并且对map[]中的元素自增,并且移动right
        	//最后更新res的值
            res = Math.max(res,++map[str[right++]-'A']+k);
            //如果当前区间长度大于不重复子序列的长度
            //说明不满足条件需要收缩
            while(right-left>res){
                map[str[left++]-'A']--;
            }
        }
        return Math.min(res,str.length);
    }
}

交替和

给出一个序列,找出一段连续子序列使得交替和最大。
交替和的定义为a[i]-a[i+1]+a[i+2]...+(-1)^(n-i)*a[n]
-10^5 <= a[i] <=10^5

第一个行为元素个数n
第二个为n个元素
输入
5
1 -2 3 -4 5
输出
15

感谢牛客大佬@小小陆和@joshua0509给出的算法。
原贴地址:https://www.nowcoder.com/discuss/471848?toCommentId=6726527

对于任意一个元素存在两个状态,加这个数和减这个数。
我们在dp数组中采用第二维来保存当前元素的加减状态,0表示加,1表示减,给出状态转移方程:
dp[i][1] = max(-a[i],dp[i-1][0]-a[i])
dp[i][0] = max(a[i],dp[i-1][1]+a[i])
最后再比较dp[n][1]dp[n][0]的大小,并返回最大值。

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] a = new int[n];
        for(int i=0;i<n;i++){
            a[i] = scanner.nextInt();
        }
        System.out.println(a2(a));
    }
    public static int a2(int[] a){
        int n = a.length;
        int[][] dp = new int[n][2];
        int res = a[0];
        dp[0][0] = a[0];
        dp[0][1]= -100000;
        for(int i=1;i<dp.length;i++){
            dp[i][1] = Math.max(-100000,dp[i-1][0]-a[i]);
            dp[i][0] = Math.max(a[i],dp[i-1][1]+a[i]);
            res = Math.max(Math.max(dp[i][0],dp[i][1]),res);
        }
        return res;
    }

多米诺骨牌/俄罗斯套娃信封

题目:https://leetcode-cn.com/problems/russian-doll-envelopes/
题目大意:
给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

上面是力扣的题目,字节的题目改成了推倒多米诺骨牌,后面的骨牌长度和宽度都要大于前面的,且不会出现相同的长度或者宽度,求多米诺骨牌的最大长度。

分析:
这道题按理来说是先排序,按照宽度升序排序,宽度相同就按照长度升序排序。

由于字节的题目中不存在长或者宽相同的元素,所以可以直接按照宽度排序,然后求长度的最长不连续上升子序列,但是我看力扣上有人说这种方法0AC,有的说60%AC。
然后杰杰是按照俄罗斯套娃的题目做的,但是不知道为什么只能过60%,怀疑可能是Java的输入超时了?不知道有没有过的大佬说下自己用的什么语言,是不是C++或者C。

//力扣原题的代码,只过了60%
class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        int maxL = 0;
        int[] dp = new int[envelopes.length];
        Arrays.sort(envelopes, (a, b) -> (a[0] == b[0] ? b[1]-a[1] : a[0]-b[0]));
        
        for(int[] env : envelopes) {
            int lo = 0, hi = maxL;
            while(lo < hi) {
                int mid = lo+(hi-lo)/2;
                if(dp[mid] < env[1])
                    lo = mid+1;
                else
                    hi = mid;
            }
            dp[lo] = env[1];
            if(lo == maxL)
                maxL++;
        }
        return maxL;
    }
}

工厂的生产方案

工厂中有N台机器,每台机器有不同的生产能力,现在要生产N个产品,求一共有几种方案。

第一行为N,第二行为N个数据表示每台机器a[i]的生产能力。
第三行为N个数据表示每个产品b[i]的型号。
第四行为P,表示最后结果要%P。
当产品编号b[i]<=a[i]的时候,表示这台机器可以生产这个产品。
输入
3
1 2 3
1 2 3
100
输出
1
只有1%100种方案
输入
3
3 3 3
1 1 1
100
6
有6%100种方案

分析:
感谢陶总的精妙算法。
采用贪心策略,首先对机器和产品按照型号升序排序。
以例子中的第二种输入为例。
第一台机器的生产能力是3,那么可以生产下标为0,1,2的三个产品,三个选择。
第二胎机器的生产能力是3,那么也可以生产下标为0,1,2的三个产品,但是需要由于第一台机器已经占用了一个产品,那么他的选择需要减去前面那台机器的选择,所以是2。
第三台机器也相同,一共能生产3中产品,但是前面两台机器占用了2个产品,所以只有1个选择。
最后相乘3*2*1 = 6

具体代码如下:

public static void main(String[] args) {
     Scanner scanner = new Scanner(System.in);
     int n = scanner.nextInt();
     int[] a = new int[n];
     int[] b = new int[n];
     int p;
     for(int i=0;i<n;i++){
         a[i] = scanner.nextInt();
     }
     for(int i=0;i<n;i++){
         b[i] = scanner.nextInt();
     }
     p = scanner.nextInt();
     System.out.println(fun(a,b,p));
 }
 public static int fun(int[] machine,int[] good,int p){
     Arrays.sort(machine);
     Arrays.sort(good);
     long sum = 1;
     int j = 0;
     int n = machine.length;
     for(int i=0;i<n;i++) {
         while (j < n && good[j] <= machine[i]) j++;
         //计算能够生产的物品个数
         //这里减去i的原因是前面的机器占用了i个物品
         int cur_count = j-i;
         if(cur_count == 0)
             return  0;
         sum *= cur_count;
         sum = sum % p;
     }
     return (int)sum;
 }

猜你喜欢

转载自blog.csdn.net/qq_33241802/article/details/107905910