1658.将x减到0的最小操作数
思路与算法:
根据题目描述,在每一次操作中,可以移除数组nums最左边和最右边的元素,因此,在所有的操作完成后,数组nums的一个前缀以及一个后缀被移除,并且它们的和恰好为x,前缀 以及后缀可以为空
记数组的长度为n,可以用left和right分别表示选择的前缀以及后缀的边界,如果left=-1,表示选择了空前缀;如果right=n表示我们选择了空后缀
由于数组nums中的元素均为正数,因此当left向右移动(即前缀的范围增加)时,它们的和是严格递增的,要想将它们的和控制在x,必须将right向右移动,可以用滑动窗口的方法来解决
初始时,left的值为-1,right为0,表示选择了空前缀以及整个数组作为后缀,用lsum和rsum分别记录前缀以及后缀的和,那么:
- 如果lsum + rsum = x,说明我们找到了一组答案,对应的操作次数为(left+1)+(n-right)
- 如果lsum + rsum > x,说明和过大,需要将right向右移动一个位置
- 如果lsum + rsum < x,说明和过小,需要将left向右移动一个位置
class Solution {public int minOperations(int[] nums, int x) {int n = nums.length;int sum = Arrays.stream(nums).sum(); //数组总和if(sum < x){return -1;}//left和right为选择的前缀和后缀的边界int right = 0;int lsum = 0,rsum = sum; //lsum和rsum分别表示前缀和和后缀和int ans = n + 1;for(int left = -1 ; left < n ; left++){ if(left != -1){ lsum += nums[left]; }while(right < n && lsum + rsum > x){ //和过大,需要将right向右移动一个位置rsum -= nums[right]; ++right;}if(lsum + rsum == x){ ans = Math.min(ans,(left + 1) + (n - right)); }}return ans > n ? -1:ans;}
}