【解题笔记】:LeetCode Contest 238

LeetCode Contest 238

1837. Sum of Digits in Base K

进制转换: n%=k ,n/=k
🐷 :

class Solution {
    public int sumBase(int n, int k) {
        int mod = 0;
        int res = 0;
        while (n != 0) {
            res  = res + n % k;
            n /= k;  
        }
        return res;
    }
}

🍀 :

class Solution {
    public int sumBase(int n, int k) {
        int ans = 0;
        while (n>0) {
            ans += n%k;
            n = n/k;
        }
        return ans;
    }
}
1838. Frequency of the Most Frequent Element

🐷 :

🍀 :

  1. 暴力解法
    每次跳过重复元素,尝试操作后回退,记录最优解
class Solution {
    public int maxFrequency(int[] nums, int k) {
        Arrays.sort(nums);
        
        int i = nums.length-1;
        int ans = 0;
        while (i >= 0) {
            int start = i;
            while (i > 0 && nums[i] == nums[i-1]) {
                i--;
            }
            
            int end = i, res = k;
            while (i >= 0) {
                res -= (nums[start]- nums[i]);
                if (res < 0) break;
                i--;
            }

            ans = Math.max(ans, start-i);
            start = i = end-1;
        }
        
        return ans;
    }
}
  1. Sliding Window
  • 升序排序,从后往前遍历(因为java int[]无法降序排序)
  • 记录的变量
    • window范围区间: 前边界start,后边界end
    • window区间和sum s u m = ∑ i = s t a r t e n d a [ i ] sum=\sum_{i=start}^{end}{a[i]} sum=i=startenda[i]
  • 遍历操作
    1. 每次尝试扩展window后边界end,把所有元素变为 n u m s [ s t a r t ] nums[start] nums[start]:
      -合法窗口条件 s u m + k > n u m s [ s t a r t ] ∗ c o u n t ; sum+k >nums[start]*count; sum+k>nums[start]count;
    2. 不合法时,窗口前边界元素出窗口
    3. 窗口的大小只增不减:前边界出窗口后,后边界继续扩展,而无需验证长度更短的window是否合法,因为我们只关心最大合法窗口的长度而非找出所有合法窗口
  • 最后一个窗口的长度即为最大合法窗口的长度但最后一个窗口并不一定是合法的窗口,只代表遍历过程中曾经有过此长度的合法窗口
class Solution {
    public int maxFrequency(int[] nums, int k) {
        Arrays.sort(nums);
        
        int start = nums.length-1, end = nums.length-1;
        int sum = 0;
        while (end >= 0) {
            sum += nums[end];
            int count = start-end+1;

            if (sum + k < nums[start]*count) {
                sum -= nums[start--];
            }
            
            end--;
        }
        
        return start-end;
    }
}

** Sliding Window题目特征总结

  1. 往往与区间有关
  2. 求解过程出现大量重合区间,大量重复的计算内容 通过双指针一前一后控制元素的进出实现sliding,以合并重复计算
    <区间和/积 | 累加/乘数组 | 概率密度函数 | 无穷积分>
  3. 通过寻找等式/不等式关系,定义合法窗口
  4. 当只关心最大区间范围or计算结果最大值时,通过尝试滑动并扩大区间的长度,减少验证窗口是否合法的次数
  5. 往往需要排序以保证结果的最优性(例如求最大区间和)
1839. Longest Substring Of All Vowels in Order

解法1:用HashSet判断是否为aeiou
🐷 :

class Solution {
    public int longestBeautifulSubstring(String word) {
        if (word.length() < 5) return 0;
        int res = 0;
        int count = 0;
        char[] temp = word.toCharArray();
        HashSet<Character> set = new HashSet<>();
        for (int i = 0; i < temp.length - 1; i++) {
            if (temp[i] - temp[i + 1] > 0) {
                set.add(temp[i]);
                if (set.size() == 5) {
                    res = Math.max(res, count);
                }
                set.clear();
                count = 0;
            } else {
                count += 1;
                set.add(temp[i]);
            }
        }
        set.add(temp[temp.length - 1]);
        if (set.size() == 5 && count != 0) res = Math.max(res, count);
        return res == 0 ? 0 : res + 1;
    }
}

解法2:创建vowels数组,按顺序依次匹配aeiou,匹配结束记录结果
依次匹配word[i],当前匹配到vowels[j]

  • 情况1: words[i]== vowels[j]继续匹配当前元音,i++
  • 情况2:words[i]== vowels[j+1]匹配下一个元音,i++, j++
  • 情况3:完全不匹配
    • a) 已经匹配到结尾,合法:记录结果
    • b) 未匹配到结尾,不合法:重新从a开始匹配
      • 若当前words[i]==a, 手动匹配一位: j=1, start = i, i++
      • 若当前words[i]!=a: j=0, start = i+1, i++

🍀 :

class Solution {
    public int longestBeautifulSubstring(String word) {
        int i = 0, j = 0; // 记录匹配位置
        int ans = 0;
        int start = 0;
        
        char[] words = word.toCharArray();
        char[] vowels = new char[]{' ','a','e','i','o','u','/'};
        
        while (i < words.length) {
            if (words[i] == vowels[j]) {
                i++;
            } else {
                if (words[i]==vowels[j+1]) {
                    i++; j++;
                } else {
                    if (vowels[j+1]=='/') {
                        ans = Math.max(ans, i-start);
                    }
                    
                    if (words[i] == 'a') {
                    	start = i++;
                    	j = 1;
                    }
                    else {
                    	start = ++i;
                    	j = 0;
                    }
                }
            }
        }
        
        if (vowels[j+1]=='/') {
            ans = Math.max(ans, i-start);
        }
        
        return ans;
    }
}
1840. Maximum Building Height
  • restrictions按building idx升序排序,正向收缩,反向收缩
  • 计算两个位置间的峰值 peek[i ~ j] = (h[i] + h[j] + i - j ) / 2;
    **注意首尾单独处理

🐷 :

class Solution {
	// Time O(nlogn)
    public int maxBuilding(int n, int[][] restrictions) {
        if (restrictions == null || restrictions.length == 0 || restrictions[0] == null ||restrictions[0].length == 0) {
            return n - 1;
        } 
        Arrays.sort(restrictions, (a, b) -> a[0] - b[0]);
        int len = restrictions.length;
        restrictions[0][1] = Math.min(restrictions[0][0] - 1, restrictions[0][1]);

        for (int i = 1; i < len; i++) {
            restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i - 1][1] + restrictions[i][0] - restrictions[i - 1][0]);
        }
        
        for (int i = len - 2; i >= 0; i--) {
            restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i + 1][1] + restrictions[i + 1][0] - restrictions[i][0]);
        }

        int res = 0;
        for (int i = 1; i < len; i++) {
            int peek = (restrictions[i][0] - restrictions[i][1] - restrictions[i - 1][0] + restrictions[i - 1][1]) / 2;
            res = Math.max(res, restrictions[i][1] + peek);
        }
        //restrictions数组的最后一个,不一定是所有楼的最后。所以还要考虑在restrictions之后还有没有楼
        res = Math.max(res, restrictions[len - 1][1] + n - restrictions[len - 1][0]);
        return res;
    }
}

🍀 :

class Solution {
    public int maxBuilding(int n, int[][] restrictions) {
        int LEN = restrictions.length;
        if (LEN==0) return n-1;

        Arrays.sort(restrictions, (a,b)-> a[0] - b[0]);
        
        restrictions[0][1] = Math.min(restrictions[0][1], restrictions[0][0]-1);
        for (int i=1; i<LEN; i++) {
            int dist = restrictions[i][0] - restrictions[i-1][0];
            restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i-1][1] + dist);
        }
        
        for (int i=LEN-2; i>=0; i--) {
            int dist = restrictions[i+1][0] - restrictions[i][0];
            restrictions[i][1] = Math.min(restrictions[i][1], restrictions[i+1][1] + dist);
        }

        int ans = Math.max(0, restrictions[LEN-1][1] + n - restrictions[LEN-1][0]);
        for (int i=1; i<LEN; i++) {
            int dist = restrictions[i][0] - restrictions[i-1][0];
            int peek = (restrictions[i][1] + restrictions[i-1][1] + dist) / 2;
            ans = Math.max(ans, peek);
        }
        return ans;
        
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值