Leetcode 第227场周赛 问题和解法

Leetcode 第227场周赛

1752. 检查数组是否经排序和轮转得到


给你一个数组 `nums` 。`nums` 的源数组中,所有元素与 `nums` 相同,但按非递减顺序排列。

如果 `nums` 能够由源数组轮转若干位置(包括 0 个位置)得到,则返回 `true` ;否则,返回 `false` 。

源数组中可能存在 **重复项** 。

**注意:**我们称数组 `A` 在轮转 `x` 个位置后得到长度相同的数组 `B` ,当它们满足 `A[i] == B[(i+x) % A.length]` ,其中 `%` 为取余运算。
  • 将数组前后连接起来,如果有符合条件的子数组则返回true
class Solution {
     
    public boolean check(int[] nums) {
     
        int len=nums.length;
        if(len==0||len==1)return true;
        int []source=new int[len*2];
        for(int i=0;i<len;i++){
     
            source[i]=nums[i];
        }
        for(int i=len,n=len*2;i<n;i++){
     
            source[i]=nums[i-len];
        }
        int start=0,end=1;
        while(end<len*2&&start-end!=len){
     
            for(;end<len*2;end++){
     
                if(source[end]<source[end-1])break;
            }
            
            if(end-start>=len)return true;
            start++;
            end=start+1;
        }
         if(end-start>=len)return true;
        return false;
    }
}

1753. 移除石子的最大得分

你正在玩一个单人游戏,面前放置着大小分别为 `a`、`b` 和 `c` 的 **三堆** 石子。

每回合你都要从两个 **不同的非空堆** 中取出一颗石子,并在得分上加 `1` 分。当存在 **两个或更多** 的空堆时,游戏停止。

给你三个整数 `a` 、`b` 和 `c` ,返回可以得到的 **最大分数** 。
  • 贪心算法,每次都从最多的两堆里面取值
class Solution {
     
    public int maximumScore(int a, int b, int c) {
     
          int[]nums={
     a,b,c};
          Arrays.sort(nums);
          int zero=0;
          int count=0;
         for(int i=0;i<3;i++)
            if(nums[i]==0)
                zero++;
          while(zero<2){
     
              zero=0;
              nums[2]--;
              nums[1]--;
              count++;
              Arrays.sort(nums);
            for(int i=0;i<3;i++)
                if(nums[i]==0)
                 zero++;
          }
          return count;
    }
}
  • 找规律
class Solution {
     
    public int maximumScore(int a, int b, int c) {
     
        if (a + b < c)
            return a + b;
        if (a + c < b)
            return a + c;
        if (b + c < a)
            return b + c;
        return (a + b + c) / 2; 
    }
}

1754. 构造字典序最大的合并字符串

给你两个字符串 word1 和 word2 。你需要按下述方式构造一个新字符串 merge :如果 word1 或 word2 非空,选择 下面选项之一 继续操作:

	如果 word1 非空,将 word1 中的第一个字符附加到 merge 的末尾,并将其从 word1 中移除。
例如,word1 = "abc" 且 merge = "dv" ,在执行此选项操作之后,word1 = "bc" ,同时 merge = "dva" 。
	如果 word2 非空,将 word2 中的第一个字符附加到 merge 的末尾,并将其从 word2 中移除。
例如,word2 = "abc" 且 merge = "" ,在执行此选项操作之后,word2 = "bc" ,同时 merge = "a" 。
返回你可以构造的字典序 最大 的合并字符串 merge 。

长度相同的两个字符串 a 和 b 比较字典序大小,如果在 a 和 b 出现不同的第一个位置,a 中字符在字母表中的出现顺序位于 b 中相应字符之后,就认为字符串 a 按字典序比字符串 b 更大。例如,"abcd" 按字典序比 "abcc" 更大,因为两个字符串出现不同的第一个位置是第四个字符,而 d 在字母表中的出现顺序位于 c 之后。


  • 贪心算法解决,需要注意的是相等的情况
class Solution {
     
    public String largestMerge(String w1, String w2) {
     
        char[] csa = w1.toCharArray(), csb = w2.toCharArray();
        int lena = csa.length, lenb = csb.length;
        char[] ans = new char[lena + lenb];
        int a = 0, b = 0, idx = 0;
        while(a < lena || b < lenb) {
     
            
            if(a >= lena) {
     
                ans[idx++] = csb[b++];
            } else if(b >= lenb) {
     
                ans[idx++] = csa[a++];
            } else if(csa[a] > csb[b]) {
     
                ans[idx++] = csa[a++];
            } else if(csa[a] < csb[b]) {
     
                ans[idx++] = csb[b++];                
            } else {
     
                // 相等
                if(look(w1.substring(a), w2.substring(b))) {
     
                    // a 比 b 大
                    ans[idx++] = csa[a++];                    
                } else {
     
                    // b 的字典序更大
                    ans[idx++] = csb[b++];
                }
            }
        }
        
        return new String(ans);
    }
    
    public boolean look(String a, String b){
     
        return a.compareTo(b) > 0;
    }
    
}
 

1755. 最接近目标值的子序列和

给你一个整数数组 `nums` 和一个目标值 `goal` 。

你需要从 `nums` 中选出一个子序列,使子序列元素总和最接近 `goal` 。也就是说,如果子序列元素和为 `sum` ,你需要 **最小化绝对差** `abs(sum - goal)` 。

返回 `abs(sum - goal)` 可能的 **最小值** 。

注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。

 
  • 将原数组平分为左右两个数组,并分别计算这两个数组所有子序列的和。对上述和进行排序,一个从小到大,一个从大到小,然后用双指针遍历这两个数组,更新答案即可。
class Solution {
     
    static int lower_bound(int[] g, int target) {
     
        /**
         * g中搜索≥target的第一个数字的位置[l,r)
         * */
        int l = 0, r = g.length;
        //if(target>g[r-1])return r;
        while (l + 1 < r) {
     
            int mid = l + (r - 1 - l) / 2;
            if (g[mid] < target) {
     
                l = mid + 1;
            } else if (g[mid] >= target) {
     
                r = mid + 1;
            }
        }
        return l;
    }

    public int minAbsDifference(int[] nums, int goal) {
     
        int n = nums.length;
        int n1 = (n + 1) / 2, n2 = n - n1;
        int[] f1 = new int[(1 << n1)], f2 = new int[(1 << n2)];
        for (int i = 0; i < (1 << n1); ++i) {
            //前半部分所有组合
            for (int j = 0; j < n1; ++j) {
     
                if (((i >> j) & 1) == 1) {
     
                    f1[i] += nums[j];
                }
            }
        }
        for (int i = 0; i < (1 << n2); ++i) {
            //后半部分所有组合
            for (int j = 0; j < n2; ++j) {
     
                if (((i >> j) & 1) == 1) {
     
                    f2[i] += nums[n1 + j];
                }
            }
        }
        Arrays.sort(f2);
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < f1.length; ++i) {
            //枚举f1
            int target = goal - f1[i];
            int index = lower_bound(f2, target);    //二分查找f2
            if (index < f2.length) {
     
                ans = min(ans, abs(f1[i] + f2[index] - goal));
            }
            if (index - 1 >= 0) {
     
                ans = min(ans, abs(f1[i] + f2[index - 1] - goal));
            }
        }
        return ans;
    }
}
 
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/
  • 欢迎访问我的博客:http://wy313.top/

你可能感兴趣的:(算法,leetcode,算法)