leetcode 2834.找出美丽数组的最小和

这道题作者一开始用的暴力解法,效果还不错,但是对于特别大的数据是过不去的。

先讲一下我暴力的思路:作者用了双指针的解法,我们可以先定义一个数组,就是把数组从1开始考虑,n个连续整数输入到里面去。

然后定义两个指针left和right,一个指向第一个元素,一个指向最后一个元素,然后让这两个数相加。如果nums[left]+nums[right]>target,我们就把right往后移动;如果nums[left]+nums[right]<target,那么就把left往前移(因为我们的初始化数组是有顺序的)。遇到==target的情况,我们需要更换数据:

由于题目中要求我们最小和,我们需要把nums[left]和nums[right]之中比较大的数字更换。那么更换成什么呢?我们知道,数组里面不能出现重复的数字,所以我们只能将这个数字变大,而不能变小,因为变小可能就会引起数组的元素重复了,并且数字变大需要变大到比这个数组的最大元素要大1,这样才能保证最小和。

那么怎么移动呢?这就是语言基础了,我们直接找到需要更改的元素位置,然后将这个元素后面的整体移动覆盖它,再在最后面更换上那个更新后的数字,这样既能保证有序,又能保证最小和(其实这里的思路具有贪心的思想,证明的话不能完全给出)。

这一道题跟某一次leetcode周赛上的题很像,但那个题是可以暴力解出来的,这个题由于数据过大,有10个样例没通过,原因就是时间超出限制。时间复杂度都已经到O(logn)2了,这没办法,思路就到这里了。

class Solution {
public:
    int minimumPossibleSum(int n, int target) {
        vector<int>nums(n+1,0);
        for(int i=0;i<n;i++){
            nums[i]=i+1;
        }
        int left=0;
        int right=n-1;
        int st=0;
        int index=0;
        while(left<right){
            if(nums[left]+nums[right]>target)
            right--;
            else if(nums[left]+nums[right]<target)
            left++;
            else{
                index=nums[n-1];
                if(right==n-1)
                nums[n-1]=index+1;
                else{
                    st=right;
                    for(int i=st;i<n;i++)
                    nums[i]=nums[i+1];
                    nums[n-1]=index+1;
                }
                left=0;
                right=n-1;
            }
        }
        int sum=0;
        for(int i=0;i<n;i++){
            sum=(sum%1000000007+nums[i]%1000000007)%1000000007;
        }
    return sum;
    }
};

至于数学的做法,应该会很好想一点:

以target为基准,我们直接可以判断:1,target-1

2,target-2

...

一直到target/2这里,target/2是直接可以选择的,没必要关乎什么奇数偶数。

前面的那些列举,我们只能选择一个去用,那我们就只选择小的就可以。

这样的话,我们其实已经完成了一部分的答案了,设m=min(target/2,n),显然,在target/2之前的那m个数字我们直接用等差数列的公式计算出来就行了也就是m*(m+1)/2。

至于剩下的那n-m个数,我们知道,刚刚已经从小于等于target的范围里选过了,所以之后需要选择比target大的那一部分了。因此,我们再次使用等差数列的公式就行了:

也就是(n-m)*(target+(target+(n-m)-1)/2,简化一下也就是(n-m)*(2*target+n-m-1)/2。

注意:有些人可能不懂target+(n-m)-1这一部分是啥,因为target后面的部分都是连续的,也就是target+1,target+2...一直加到n-m-1的时候才停止,加上target本身一共n-m个。这个式子就是这样来的。

上代码:

class Solution {
public:
    int minimumPossibleSum(int n, int target) {
        long long m=min(target/2,n);
        return (m*(m+1)+(n-m-1+2*target)*(n-m))/2%1000000007;
    }
};

相关推荐

  1. leetcode 2834.美丽

    2024-03-10 20:36:06       17 阅读
  2. 力扣2834. 美丽

    2024-03-10 20:36:06       19 阅读
  3. leetcode 2386. 第 K 大根堆】

    2024-03-10 20:36:06       20 阅读
  4. 两个公倍数大公约数

    2024-03-10 20:36:06       12 阅读
  5. LeetCode: 2779. 美丽

    2024-03-10 20:36:06       7 阅读
  6. LeetCode】2386. 第 K 大

    2024-03-10 20:36:06       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-10 20:36:06       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-10 20:36:06       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-10 20:36:06       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-10 20:36:06       18 阅读

热门阅读

  1. MySQL的页与行格式

    2024-03-10 20:36:06       27 阅读
  2. DPN网络

    DPN网络

    2024-03-10 20:36:06      20 阅读
  3. 银行app软件使用技巧,避免被限制非柜面交易。

    2024-03-10 20:36:06       55 阅读
  4. 初识C语言—字符串、转义字符、注释

    2024-03-10 20:36:06       21 阅读
  5. vue3注册全局组件

    2024-03-10 20:36:06       18 阅读
  6. Docker Register 搭建私有镜像仓库

    2024-03-10 20:36:06       20 阅读
  7. Linux 系统上卸载 Docker

    2024-03-10 20:36:06       21 阅读
  8. 在 Docker 环境下安装 OpenWrt

    2024-03-10 20:36:06       25 阅读
  9. Docker修改网段

    2024-03-10 20:36:06       22 阅读
  10. Kotlin 中的数据类

    2024-03-10 20:36:06       21 阅读