Leetcode热题_by230716

1.6927 minimum index of a validsplit

353周leetcode周赛题、中等

题目:

如果元素 x 在长度为 m 的整数数组 arr 中满足 freq(x) * 2 > m ,那么我们称 x 是 支配元素 。其中 freq(x) 是 x 在数组 arr 中出现的次数。注意,根据这个定义,数组 arr 最多 只会有 一个 支配元素。

给你一个下标从 0 开始长度为 n 的整数数组 nums ,数据保证它含有一个支配元素。
你需要在下标 i 处将 nums 分割成两个数组 nums[0, …, i] 和 nums[i + 1, …, n - 1] ,如果一个分割满足以下条件,我们称它是 合法 的:

0 <= i < n - 1
nums[0, …, i] 和 nums[i + 1, …, n - 1] 的支配元素相同。
这里, nums[i, …, j] 表示 nums 的一个子数组,它开始于下标 i ,结束于下标 j ,两个端点都包含在子数组内。特别地,如果 j < i ,那么 nums[i, …, j] 表示一个空数组。

请你返回一个 合法分割 的 最小 下标。如果合法分割不存在,返回 -1 。

示例 1:
输入:nums = [1,2,2,2]
输出:2

解释:我们将数组在下标 2 处分割,得到 [1,2,2] 和 [2] 。
数组 [1,2,2] 中,元素 2 是支配元素,因为它在数组中出现了 2 次,且 2 * 2 > 3 。
数组 [2] 中,元素 2 是支配元素,因为它在数组中出现了 1 次,且 1 * 2 > 1 。
两个数组 [1,2,2] 和 [2] 都有与 nums 一样的支配元素,所以这是一个合法分割。
下标 2 是合法分割中的最小下标。

示例 2:
输入:nums = [2,1,3,1,1,1,7,1,2,1]
输出:4

解释:我们将数组在下标 4 处分割,得到 [2,1,3,1,1] 和 [1,7,1,2,1] 。
数组 [2,1,3,1,1] 中,元素 1 是支配元素,因为它在数组中出现了 3 次,且 3 * 2 > 5 。
数组 [1,7,1,2,1] 中,元素 1 是支配元素,因为它在数组中出现了 3 次,且 3 * 2 > 5 。
两个数组 [2,1,3,1,1] 和 [1,7,1,2,1] 都有与 nums 一样的支配元素,所以这是一个合法分割。
下标 4 是所有合法分割中的最小下标。

示例 3:
输入:nums = [3,3,3,3,7,2,2]
输出:-1
解释:没有合法分割。

提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
nums 有且只有一个支配元素。

题解:

我们需要遍历切割点,将数组分为左右,并且记录左右两边的支配元素(以及有无)。
每次切割都去计算一次两边的支配元素?
后发现每次迭代后在上一次迭代的基础作出相应调整即可:

  • 用两个HashMap记录左右两边的数字和出现次数
    维护:-切割点往右移一位的同时,
    • 在左边hashMap中加入这个数字:hashMap中已有,则value+1,若暂无,则put,value为1;
    • 在右边hashMap中将对应的value-1。
  • 记录两边最多的数字max_l,max_r
    • 原因:找左右两边List的支配元素时,若存在,则必为出现最多的元素;那么判断max_l/max_r是否满足支配元素的条件就可知两边是否有支配元素
    • 维护:切割点往右移一位的同时,
      • 如果变动的数字与左边max_l相同,则max_l不变,否则可能改变,重新选出max_l
      • 如果变动的数字与右边max_r不同,则max_r不变,否则可能改变,重新选出max_r

最后判断即可:

2*left_map.get(max_l)>i+1&&2*right_map.get(max_r)>nums.size()-i-1&&max_l==max_r

代码

public static int minimumIndex(List<Integer> nums) {
        HashMap<Integer,Integer> left_map = new HashMap<>();
        HashMap<Integer,Integer> right_map = new HashMap<>();

        //初始化right_map,以及找出max_r,初始状态右边List即使整个List
        for(int i=0;i<nums.size();++i){
            right_map.put(nums.get(i),right_map.get(nums.get(i))!=null? right_map.get(nums.get(i))+1:1);
        }
        int max_r=nums.get(0);
        for(int i:right_map.keySet()){
            if(right_map.get(i)>right_map.get(max_r)){
                max_r=i;
            }
        }

        int max_l=nums.get(0);
        for(int i=0;i<nums.size()-1;++i){
            //调整左右两边的hashMap
            left_map.put(nums.get(i),left_map.get(nums.get(i))!=null?left_map.get(nums.get(i))+1:1);
            right_map.put(nums.get(i),right_map.get(nums.get(i))-1);

            //若变动的元素不是左边最大值,则max_l可能变化,重新计算
            if(nums.get(i)!=max_l){
                if(left_map.get(nums.get(i))>left_map.get(max_l)){
                    max_l = nums.get(i);
                }
            }

            //若变动的元素是右边最大值,移向左边,则max_r可能变化,重新计算
            if(nums.get(i)==max_r){
                for(int m:right_map.keySet()){
                    if(right_map.get(m)>right_map.get(max_r)){
                        max_r = m;
                    }
                }
            }

            //判断两边是否有支配元素且相同
            if(2*left_map.get(max_l)>i+1&&2*right_map.get(max_r)>nums.size()-i-1&&max_l==max_r){
                return i;
            }

        }
        return -1;
    }

提交结果:

在这里插入图片描述
912/915,超时!!算法依然性能不够

后发现没有对题目所给条件进行优化

正确版本

因为要求两个支配元素相同,在这里插入图片描述
所以只需先找到出现最多的元素以及出现次数(利用hashMap); 接着在遍历过程中

  • 记录该元素在左边出现次数(也得到了在右边的出现次数count-count_l)
  • 判断是否同时是两边的支配元素

修订代码

public static int minimumIndex(List<Integer> nums) {
        HashMap<Integer,Integer> map = new HashMap<>();
        int max=nums.get(0);
        int count = 1;

        //初始化map,以及找出出现最多的元素max,以及它出现的次数count
        for(int i=0;i<nums.size();++i){
            map.put(nums.get(i),map.get(nums.get(i))!=null? map.get(nums.get(i))+1:1);
        }
        for(int i:map.keySet()){
            if(map.get(i)>count){
                max=i;
                count=map.get(i);
            }
        }

        //不在需要记录右边的,因为count_r=count-count_l
        int count_l=0;
        for(int i=0;i<nums.size()-1;++i){
            //如果变动了max
            if(nums.get(i)==max){
                count_l++;
            }

            //判断两边是否有支配元素且相同
            if(2*count_l>i+1&&2*(count-count_l)>nums.size()-i-1){
                return i;
            }

        }
        return -1;
    }

2. 6929 Maximum Beauty of an Array After Applying Operation

353周leetcode周赛题、中等

题目:

给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。

在一步操作中,你可以执行下述指令:
在范围 [0, nums.length - 1] 中选择一个 此前没有选过 的下标 i 。
将 nums[i] 替换为范围 [nums[i] - k, nums[i] + k] 内的任一整数。
数组的 美丽值 定义为数组中由相等元素组成的最长子序列的长度。

对数组 nums 执行上述操作任意次后,返回数组可能取得的 最大 美丽值。

注意:你 只 能对每个下标执行 一次 此操作。

数组的 子序列 定义是:经由原数组删除一些元素(也可能不删除)得到的一个新数组,且在此过程中剩余元素的顺序不发生改变。

题解

由子序列的定义分析可知,因为可以删除一些元素,所以可以理解为我们可以从中“自由的挑选”
原数组的最大美丽值和排序后的最大美丽值相等,分析如下:在这里插入图片描述
而对于排序后数组的最大美丽值,就很好找了。只要找到最大的 右边界-左边界>2k的 区间即可,

代码:

//实现的并不太好,看个乐子就行
 public int maximumBeauty(int[] nums, int k) {
        Arrays.sort(nums);
        
        int len=1;
        for(int i=0;i<nums.length;++i){
            int j=i+1;
            while(j<nums.length&&nums[j]-nums[i]<=2*k){
                ++j;
            }
            len = Math.max(j - i, len);
            if(j>=nums.length){
                return len;
            }
            while(i<nums.length&&nums[j]-nums[i]>2*k){
                ++i;
            }
            i--;
        }
        return len;
    }

可以采用滑动窗口的方式解决

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值