Open azl397985856 opened 2 years ago
class Solution { public int solve(int[] nums, int target) { //Arrays.sort(nums); int l = 0, r = 0; int sum = -target; for (int num : nums) { sum += num; } if (sum == 0) return nums.length; int cur = 0; int res = 0; while (r < nums.length) { cur += nums[r]; while (cur >= sum && r >= l) { if (cur == sum) { res = Math.max(res, r - l + 1); } cur -= nums[l]; l++; } r++; } return res == 0 ? -1 : nums.length - res; } }
思路 滑动窗口找中间n个数字,使得剩下的数和为target。即中间n个数的和 = sum(nums) - target
代码
class Solution:
def solve(self, nums, target):
l = 0
r = 0
s = 0
res = []
rest_target = sum(nums) - target
if rest_target < 0:
return -1
if rest_target == 0:
return len(nums)
while r < len(nums):
s += nums[r]
while s > rest_target:
s -= nums[l]
l += 1
if s == rest_target:
res.append(len(nums) - (r-l+1))
r += 1
if res:
return min(res)
else:
return -1
复杂度 时间 O(n) 空间 O(1) 可以列出n种可能性,也可以直接存最小值
class Solution:
def solve(self, A, target):
if not A and not target: return 0
target = sum(A) - target
ans = len(A) + 1
i = t = 0
for j in range(len(A)):
t += A[j]
while i <= j and t > target:
t -= A[i]
i += 1
if t == target: ans = min(ans, len(A) - (j - i + 1))
return -1 if ans == len(A) + 1 else ans
思路:
滑动窗口
复杂度分析:
代码(C++):
class solution {
public:
int solve(vector<int>& nums, int target) {
if (target == 0) return 0;
int len = nums.size();
int sum = 0;
for (auto n : nums)
sum += n;
int res = len;
int winSum = sum - target;
if (winSum == 0) return len;
else if (winSum < 0) return -1;
for (int r = 0, l = 0, tmpSum = 0; r < len; ++r) {
tmpSum += nums[r];
while (tmpSum >= winSum && l < len) {
if (tmpSum == winSum)
res = min(len - r + l - 1, res);
tmpSum -= nums[l];
++l;
}
}
return res == len ? -1 : res;
}
};
class Solution:
def solve(self, nums, target):
l = 0
r = 0
s = 0
res = []
rest_target = sum(nums) - target
if rest_target < 0:
return -1
if rest_target == 0:
return len(nums)
while r < len(nums):
s += nums[r]
while s > rest_target:
s -= nums[l]
l += 1
if s == rest_target:
res.append(len(nums) - (r-l+1))
r += 1
if res:
return min(res)
else:
return -1
class Solution:
def solve(self, nums, target):
l = 0
r = 0
s = 0
res = []
rest_target = sum(nums) - target
if rest_target < 0:
return -1
if rest_target == 0:
return len(nums)
while r < len(nums):
s += nums[r]
while s > rest_target:
s -= nums[l]
l += 1
if s == rest_target:
res.append(len(nums) - (r-l+1))
r += 1
if res:
return min(res)
else:
return -1
++
给你一个整数数组 nums
和一个整数 x
。每一次操作时,你应当移除数组 nums
最左边或最右边的元素,然后从 x
中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x
恰好 减到 0
,返回 最小操作数 ;否则,返回 -1
。
#include <numeric>
class Solution {
public:
int minOperations(vector<int>& nums, int x) {
int sum = std::accumulate(nums.begin(), nums.end(), 0);
int target = sum - x;
int i = 0, j= 0;
sum = 0;
int res = -1;
while(j < nums.size()){
// j右移,扩大窗口
sum += nums[j++];
//当sum>target, 需要i右移
while(sum > target && i < nums.size()){
sum -= nums[i++];
}
// 已经找到一种符合目标的情况
if(sum == target){
res = max(res, j - i);
}
// sum<target,进入下一个循环
}
return res != -1? nums.size() - res: -1;
}
};
思路:反求nums中连续元素和为sum-x的元素最大值。
func maxScore(cardPoints []int, k int) int {
n := len(cardPoints)
// 滑动窗口大小为 n-k
windowSize := n - k
// 选前 n-k 个作为初始值
sum := 0
for _, pt := range cardPoints[:windowSize] {
sum += pt
}
minSum := sum
for i := windowSize; i < n; i++ {
// 滑动窗口每向右移动一格,增加从右侧进入窗口的元素值,并减少从左侧离开窗口的元素值
sum += cardPoints[i] - cardPoints[i-windowSize]
minSum = min(minSum, sum)
}
total := 0
for _, pt := range cardPoints {
total += pt
}
return total - minSum
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
时间复杂度:O(n) 空间复杂度:O(1)
主要是否能够转换问题,将原题的要求变成求滑动窗口的值为【数组所有的值的和减去target】
import java.util.*; class Solution { public int solve(int[] nums, int target) { if(target==0)return 0; if(nums==null||nums.length==0)return -1; int res =nums.length+1; int temp = 0; int left = 0,right =nums.length-1; for(int i=0;i<nums.length;i++){ temp+=nums[i]; if(temp>=target){ left = i; break; } }·· if(temp<target)return -1; if(temp==target){ res = Math.min(res,left+1); } while (left>=0){ temp -= nums[left--]; while (temp<target&&right>0){ temp+=nums[right--]; } if(temp==target)res=Math.min(res,left+nums.length-right); } return res==nums.length+1?-1:res; } }
时间复杂度:O(n)
空间复杂度:O(1)
思路 Sliding Window
int solve(vector
curSum -= nums[left]; // 扔掉滑动窗口最左侧的数
left++;
}
}
return maxLen == 0 ? -1 : N - maxLen;
}
时间复杂度:O(n) 空间复杂度:O(1)
const minOperations = function (nums, x) {
let len = nums.length,
best = 0;
for (let i = 1; i < len; i++) nums[i] += nums[i - 1];
let y = nums[len - 1] - x;
if (y < 0) return -1;
if (y === 0) return len;
for (let i = -1, j = (l = 0); i < len - best && l <= x; l = nums[++i]) {
while (nums[j] - l < y) j++;
if (nums[j] - l === y) best = Math.max(best, j - i);
}
return best > 0 ? len - best : -1;
};
class Solution {
solve(nums, target) {
let sums = nums.reduce((p, c) => p + c, 0);
target = sums - target;
if (nums.length === 0) {
return target === 0 ? 0 : -1;
} else {
if (target === 0) return nums.length
}
let max = -1;
let left = 0, right = 0;
let subSum = 0;
while (right < nums.length && left <= right) {
subSum += nums[right];
//console.log(subSum)
while (subSum >= target) {
if (subSum === target) {
max = Math.max(max, right - left + 1)
}
subSum -= nums[left];
left++
}
right++;
}
return max === -1 ? -1 : nums.length - max;
}
}
滑动窗口
class Solution:
def solve(self, nums, target):
if not nums and not target:
return 0
target = sum(nums) - target
ans = len(nums) + 1
left = right = 0
for window_end in range(len(nums)):
right += nums[window_end]
while left <= window_end and right > target:
right -= nums[left]
left += 1
if right == target:
ans = min(ans, len(nums) - (window_end - left + 1))
return -1 if ans == len(nums) + 1 else ans
Sliding window + HashMap
int solve(vector<int>& nums, int target) {
if(nums.size() == 0){
return target == 0? 0: -1;
}
if(target == 0) return 0;
map<int, int> right = {{0, 0}};
int ans = INT_MAX;
int cur = 0;
for(int i =0; i < nums.size(); i++){
cur += nums[i];
if(cur == target){
ans = i+1;
}
if(cur > target){
break;
}
right[cur]=i+1;
}
if(cur<target){
return -1;
}
cur = 0;
for(int i =nums.size()-1; i > -1; i--){
cur += nums[i];
if(cur > target){
break;
}
if (right.find(target-cur) != right.end()){
int new_length = nums.size()-i+right.find(target-cur)->second;
if(new_length < ans){
ans = new_length;
}
}
}
return ans == INT_MAX? -1:ans;
}
Time: O(N) Space: O(N)
遍历
def fun(nums,target):
nums.reverse()
sum=0
for i in range(len(nums)):
sum+=nums[i]
if sum==target:
print(i+1)
break
elif sum>target:
print(-1)
break
if i==len(nums)-1:
print(-1)
nums = [3, 1, 1, 2, 5, 1, 1]
target = 7
fun(nums,target)
class Solution {
public int solve(int[] nums, int target) {
int n = nums.length;
if (n == 0) {
if (target == 0)
return 0;
else
return -1;
}
if (target == 0)
return 0;
int sum = 0;
for (int num : nums) sum += num;
if (sum == target)
return n;
target = sum - target;
HashMap<Integer, Integer> map = new HashMap<>();
int t = 0;
int ans = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
t += nums[i];
if (t == target)
ans = Math.min(n - 1 - i, ans);
if (map.containsKey(t - target))
ans = Math.min(ans, n - (i - map.get(t - target)));
map.put(t, i);
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
}
将问题转化为找最长的子数组, sum(subarray) == target,使用滑动窗口解决
class Solution:
def solve(self, nums, target):
if not nums and target == 0:
return 0
ans = -1
r = 0
target = sum(nums) - target
curr_sum = 0
for l in range(len(nums)):
while r < len(nums) and curr_sum < target:
curr_sum += nums[r]
r += 1
if curr_sum == target:
ans = max(ans, r - l)
curr_sum -= nums[l]
return len(nums) - ans if ans != -1 else -1
滑动窗口,左指针向右遍历,然后右指针向左遍历,同时左指针向左回退
class Solution {
solve(nums, target) {
if (target === 0) return 0;
let len = nums.length;
let p = 0;
let q = len - 1;
let total = 0;
let res = Infinity;
while (p < len - 1) {
total += nums[p];
if (total === target) {
res = Math.min(res, p + 1);
break;
} else if (total < target) {
p++;
} else {
break;
}
}
p = Math.min(p, len - 2);
while (q > p) {
total += nums[q];
while (total > target && p >= 0) {
total -= nums[p];
p--;
}
if (total === target) {
res = Math.min(res, len - q + p + 1);
q--;
} else if (total < target) {
q--;
} else {
break;
}
}
return res < Infinity ? res : -1;
}
}
时间复杂度:O(n) 空间复杂度:O(1)
可以转换成窗口大小固定的滑动窗口求最小值,这样剩下的就是最大值
JavaScript Code:
/**
* @param {number[]} cardPoints
* @param {number} k
* @return {number}
*/
var maxScore = function(cardPoints, k) {
let sum = 0
let min = 0
let len = cardPoints.length - k
cardPoints.forEach((e, index) => {
if (index < len) {
min += e
}
sum += e
})
let l = 1
let r = len
let res = min
while(r < cardPoints.length) {
min = min - cardPoints[l-1] + cardPoints[r]
res = Math.min(res, min)
l++
r++
}
return sum - res
};
复杂度分析
令 n 为数组长度。
LC的1658题 思路: 求两边最小等于求中间最大,先对整个数组求和,减去target。然后开始求滑动窗口的值,
func minOperations(nums []int, x int) int {
sum := 0
for i:=0;i<len(nums);i++{
sum += nums[i]
}
if sum == x{
return len(nums)
}
if sum < x{
return -1
}
sum -= x
l, r := 0,0
out := 0
for ;r<len(nums);r++{
sum -= nums[r]
for sum < 0&&l <= r{
sum += nums[l]
l++
}
if sum == 0{
if r-l+1 > out{
out = r-l+1
}
}
}
if out == 0{
return -1
}
return len(nums) - out
}
时间复杂度O(n) 空间复杂度O(1)
步骤
class Solution {
public int solve(int[] nums, int target) {
int sumNums = 0,sum = 0;
for(int i=0;i<nums.length;i++){
sumNums+=nums[i];
}
if(sumNums==target){
return nums.length;
}else if(sumNums<target){
return -1;
}
target = sumNums-target;
int left = 0,right = 0,length = -1;
while(right<nums.length){
sum+=nums[right++];
if(sum==target){
length = Math.max(length,right-left);
}
while(sum>target){
sum-=nums[left++];
if(sum==target){
length = Math.max(length,right-left);
}
}
}
if(length==-1){
return -1;
}
return nums.length-length;
}
}
时间:O(n)
空间:O(1)
class Solution:
def solve(self, nums, target):
sumnum = sum(nums)
tar = sumnum - target
if not target:
return 0
if sumnum < target:
return -1
if not tar:
return len(nums)
l = 0
x = 0
ans = -1
xx = []
for r in range(len(nums)):
x += nums[r]
while x >= tar:
if x == tar:
ans = max(ans,r - l + 1)
x -= nums[l]
l += 1
return len(nums) - ans if ans != -1 else -1
const decTargetToZero = (arr, target) => {
let leftIdx = 0;
let rightIdx = arr.length - 1;
let sumL = 0;
let sumR = 0;
let foundL = false;
let foundR = false;
while (leftIdx < arr.length - 1 && sumL <= target) {
if (sumL === target) {
foundL = true;
break;
}
sumL += arr[leftIdx];
leftIdx++;
}
while (rightIdx > 0 && sumR <= target) {
if (sumR === target) {
foundR = true;
break;
}
sumR += arr[rightIdx];
console.log(sumR);
rightIdx--;
}
console.log(leftIdx, rightIdx);
if (foundL && !foundR) return leftIdx + 1;
if (foundR && !foundL) return arr.length - rightIdx;
if (foundL && foundR) return Math.min(leftIdx, arr.length - rightIdx - 1);
return -1;
};
nums
的总和 sum
, 然后维护一个窗口, 如果存在这么一个窗口, 使得窗口的总和 windowSum
= sum - target
, 此时窗口外的元素总和就是 target
了, 删除窗口外元素即可满足题目条件.class Solution {
solve(nums, target) {
if (target === 0) { return 0 }
const sum = nums.reduce((calc, num) => calc += num, 0)
if (sum < target) { return -1 }
let left = 0, right = 0, ans = -1, windowSum = 0
while(right < nums.length) {
windowSum += nums[right]
while (windowSum >= sum - target) {
if (windowSum === sum - target) {
const count = nums.length - (right - left + 1)
ans = (ans === -1 || count < ans) ? count : ans
}
windowSum -= nums[left]
left++
}
right++
}
return ans
}
}
参考题解 滑动窗口 + 二分法
class Solution:
def solve(self, A, target):
if not A and not target: return 0
target = sum(A) - target
ans = len(A) + 1
i = t = 0
for j in range(len(A)):
t += A[j]
while i <= j and t > target:
t -= A[i]
i += 1
if t == target: ans = min(ans, len(A) - (j - i + 1))
return -1 if ans == len(A) + 1 else ans
时间: O(n)
空间:O(1)
class Solution: def solve(self, A, target): if not A and not target: return 0 target = sum(A) - target ans = len(A) + 1 i = t = 0
for j in range(len(A)):
t += A[j]
while i <= j and t > target:
t -= A[i]
i += 1
if t == target: ans = min(ans, len(A) - (j - i + 1))
return -1 if ans == len(A) + 1 else ans
class Solution:
def solve(self, nums, target):
if target == 0:
return 0
psum = sum(nums)
if psum < target:
return -1
ans = len(nums) + 1
ssum = 0
ssumcnt = 0
for i in range(len(nums)-1, -1, -1):
psum -= nums[i]
while psum + ssum < target:
ssum += nums[-1-ssumcnt]
ssumcnt += 1
if psum + ssum == target:
ans = min(ans, i+ssumcnt)
if ans > len(nums):
return -1
return ans
time complexity: O(N) space complexity: O(1)
int solve(vector<int>& nums, int target) {
/// transfer this question to
//
// find [i j] = totalSum - target;
// [i j] = preSum[j] - preSum[i-1];
if(target == 0)
return 0;
int sum=0;
vector<int> preSum(nums.size()+1, 0);
for(int i=0; i< nums.size(); i++)
{
sum += nums[i];
preSum[i+1] = sum;
}
if(sum<target)
return -1;
target = sum - target;
unordered_map<int, int> record;
record[0] =0;
int ret = INT_MIN;
for(int i=0; i< preSum.size(); i++){
int val = preSum[i] - target;
if(record.count(val))
{
ret = max(ret, i - record[val]);
}
record[preSum[i]] =i;
}
return ret==INT_MIN? -1: nums.size() - ret;
}
转化成寻找和为sum-target的最长子数组的长度
class Solution:
def solve(self, nums, target):
if not nums and not target:
return 0
if not nums and target:
return -1
target = sum(nums) - target #转换成和为sum-target的最小连续子串
ans = len(nums)+1
i = t = 0
for j in range(len(nums)):
t += nums[j]
while i <= j and t > target:
t -= nums[i]
i += 1
if t == target:
ans = min(ans,len(nums)-(j-i+1))
return -1 if ans == len(nums) + 1 else ans
时间复杂度:O(n) 空间复杂度:O(1)
思路
代码
class Solution:
def solve(self, nums, target):
if not nums and not target:
return 0
target = sum(nums) - target
ans = len(nums) + 1
i = t = 0
for j in range(len(nums)):
t += nums[j]
while i <= j and t > target:
t -= nums[i]
i += 1
if t == target:
ans = min(ans, len(nums) - (j - i + 1))
return -1 if ans == len(nums) + 1 else ans
复杂度分析
滑动窗口
class Solution:
def solve(self, nums, target):
n = len(nums)
target = sum(nums) - target
if target < 0:
return -1
if target == 0:
return n
l, r, window, lenth = 0, 0, 0, 0
while(r < n):
window += nums[r]
while(window >= target):
if window == target:
lenth = max(lenth, r - l + 1)
window -= nums[l]
l += 1
r += 1
return n - lenth if lenth > 0 else -1
复杂度分析
class Solution {
// 一共 len 张卡牌
// 每次从头部或者尾部取一张卡牌,一共取K次,要求,取出的卡牌之和最大
// 等价于剩下的 len - K 张卡牌之和最小
// 并且剩下的len - K张卡牌必须是连续的
// 因此很容易想到滑动窗口
public int maxScore(int[] cardPoints, int k) {
int len = cardPoints.length;
int min = 0; // 记录已知的len-k张卡牌之和的最小值
int now = 0; // 记录当前的len-k张卡牌之和
int total = 0;// 记录卡牌总和
int rest = len - k; // 需要剩下的卡牌数量,即滑动窗口大小
for (int i = 0 ; i < rest ; i ++){
now += cardPoints[i]; // 第0 到 第len-k张卡牌之和
}
min = now;
total = now;
for (int i = rest ; i < len ; i ++){
now = now + cardPoints[i]; // 每次移动窗口都加上窗口右边的一个元素
now = now - cardPoints[i - rest]; // 同时减去左边的元素
min = Math.min(min,now); // 更新最小值
total = total + cardPoints[i]; // 记录卡牌总和
}
return total - min; // 卡牌总和减去剩下卡牌的最小值 = 取走卡牌的最大值
}
}
滑动
LeetCode 1658
class Solution {
public int minOperations(int[] nums, int x) {
int n = nums.length;
int l = 0, r = 0, sum = 0, sumNum = 0;
int maxLen = -1;
for(int num : nums){
sum += num;
}
int count = sum - x;
if(count < 0){
return -1;
}
while(r < n){
sumNum += nums[r];
while(sumNum > count){
sumNum -= nums[l];
l++;
}
if(sumNum == count){
maxLen = Math.max(maxLen, r - l + 1);
}
r++;
}
if(maxLen == -1) return -1;
else return n - maxLen;
}
}
LeetCode 1423
class Solution {
public int maxScore(int[] cardPoints, int k) {
int n = cardPoints.length;
int i = 0, ms = 0, k2 = k;
for(; i < k; i++){
ms += cardPoints[i];
}
int max = ms;
for(int r = n - 1; r >= n - k; r--){
ms = ms + cardPoints[r] - cardPoints[--i];
if(ms > max){
max = ms;
}
}
return max;
}
}
复杂度分析
找连续子串的和为sum(nums) - target
class Solution {
public int solve(int[] nums, int target) {
int sum = Arrays.stream(nums).sum();
if (sum < target) {
return -1;
}
if (sum == target) {
return nums.length;
}
int winSum = 0;
int maxLen = 0;
int left = 0;
for (int right=0; right<nums.length; right++) {
winSum += nums[right];
while (winSum > sum - target && left <= right) {
winSum -= nums[left];
left++;
}
if (winSum == sum - target) {
maxLen = Math.max(maxLen, right - left + 1);
}
}
return maxLen == 0 ? -1 : nums.length - maxLen;
}
}
TC: O(n) SC: O(1)
滑动窗口
要删的是两边的,不连续,那留下来的是中间的,这不就连续了么。
所以转换思想,就是要找出和不大于sum-target的连续子序列,最后返回len-子序列的长度即可
int solve(vector<int>& nums, int target) {
int sum = accumulate(nums.begin(),nums.end(),0) - target;
if(sum<0) return -1;
int len = nums.size();
if(sum == 0) return len;
int l = 0;
int maxlen = 0;
int count = 0;
for(int r = 0;r<len;r++){
count+=nums[r];
while(count>=sum){
if(count == sum) maxlen = max(r-l+1,maxlen);
count-=nums[l++];
}
}
return maxlen == 0?-1:len-maxlen;
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public:
int maxScore(vector<int>& cardPoints, int k) {
int sum= 0;
for (int num:cardPoints){
sum+=num;
}
// 滑动窗口的大小已经固定,滑动窗口的值最小时值,手中的牌拿到的最大
int size = cardPoints.size();
int w_size =size-k;
int pos1 = 0;
int pos2 = 1;
int rest_sum = 0;
int min_rest_sum=0;
while (pos2<=size){
rest_sum+=cardPoints[pos2-1];
if(pos2++<=w_size){
min_rest_sum = rest_sum;
continue;
}
rest_sum-=cardPoints[pos1++];
min_rest_sum = min(min_rest_sum,rest_sum);
}
return sum-min_rest_sum;
}
};
class Solution:
def solve(self, nums, target):
if not target:
return 0
if not nums:
return -1
inner_target = sum(nums) - target
i = 0
s = 0
res = len(nums) + 1
for j in range(len(nums)):
s += nums[j]
while i <= j and s > inner_target:
s -= nums[i]
i += 1
if s == inner_target:
res = min(res, len(nums) - (j - i + 1))
return -1 if res == len(nums)+1 else res
TC: O(N) SC: O(1)
// 1-27
int solve(vector<int>& nums, int target) {
if (target == 0) return 0;
if (nums.size() == 0) return -1;
int sum = 0, k = 0;
for (auto i : nums) sum += i;
k = sum - target;
if (sum < target) return -1;
int len = nums.size();
if (sum == target) return len;
int l = 0, r = -1, winsum = 0, ans = len + 1;
while (r < len) {
winsum += nums[++r];
while (winsum >= k && l <= r) {
if (winsum == k) ans = min(ans, len-r+l-1);
winsum -= nums[l++];
}
}
return ans == len + 1 ? -1 : ans;
}
时间复杂度 O(n)
空间复杂度 O(n)
class Solution:
def minOperations(self, nums: List[int], x: int) -> int:
n, l, r, s = len(nums), -1, 0, 0
target = sum(nums) - x
ans = -1
while r < n:
s += nums[r]
r += 1
if s < target:
continue
while s > target and l < n - 1:
l += 1
s -= nums[l]
if s == target:
ans = max(ans, r - l - 1)
return ans if ans < 0 else (n - ans)
滑动窗口
class Solution {
public int solve(int[] nums, int target) {
int sum = Arrays.stream(nums).sum();
if (sum < target) {
return -1;
}
if (sum == target) {
return nums.length;
}
int winSum = 0;
int maxLen = 0;
int left = 0;
for (int right=0; right<nums.length; right++) {
winSum += nums[right];
while (winSum > sum - target && left <= right) {
winSum -= nums[left];
left++;
}
if (winSum == sum - target) {
maxLen = Math.max(maxLen, right - left + 1);
}
}
return maxLen == 0 ? -1 : nums.length - maxLen;
}
}
Time O(N) SpaceO(1)
滑动窗口
class Solution {
public int maxScore(int[] cardPoints, int k) {
//逆向思维 我们可以通过求出剩余卡牌点数之和的最小值,来求出拿走卡牌点数之和的最大值
//由于剩余卡牌是连续的,使用一个固定长度为 n-k 的滑动窗口对数组
//cardPoints 进行遍历,求出滑动窗口最小值,然后用所有卡牌的点数之和减去该最小值,即得到了拿走卡牌点数之和的最大值。
int sum=0,minSum=0;
int n=cardPoints.length;
for (int i = 0; i <n ; i++) {
sum+=cardPoints[i];
}
for (int i = 0; i <n-k ; i++) {
minSum+=cardPoints[i];
}
int tmpsum=minSum;
for (int i = n-k; i <n; i++) {
tmpsum+=cardPoints[i]-cardPoints[i-(n-k)];
minSum=Math.min(minSum,tmpsum);
}
return sum-minSum;
}
}
复杂度分析 时间复杂度:$O(n)$ n为卡牌长度 空间复杂度:$O(1)$
import java.util.*;
class Solution {
public int solve(int[] nums, int target) {
int len = nums.length;
int sum = 0;
for(int i = 0;i < len;i++) {
sum += nums[i];
}
int newTarget = sum - target;
if(newTarget == 0) return len;
int left = 0;
int curSum = 0;
int maxLen = 0;
for(int i = 0;i < len;i++) {
curSum += nums[i];
while(curSum >= newTarget && i >= left) {
if(curSum == newTarget) {
maxLen = Math.max(maxLen, i - left + 1);
}
curSum -= nums[left];
left++;
}
}
return maxLen == 0 ? -1 : len - maxLen;
}
}
滑动窗口,题目难度不大,但是这个边界判定把我坑死了,wa了几发
class Solution {
solve(nums, target) {
if (target === 0) {
return 0;
}
if (nums.length === 0) {
return -1;
}
// 即求解和为 sum - target 的连续子数组
// 求解出最长的满足条件的数组,即为需要弹出最少数字的数组
const sum = nums.reduce((pre, cur) => (pre + cur)) - target;
if (sum === 0) {
return nums.length;
}
let left = 0, right = 0;
let curSum = 0, maxLen = 0;
while (right < nums.length) {
const num = nums[right++];
curSum += num;
while (left < right && curSum >= sum) {
if (curSum === sum) {
maxLen = Math.max(maxLen, right - left);
}
const num = nums[left++];
curSum -= num;
}
}
return maxLen === 0 ? -1 : nums.length - maxLen;
}
}
时间:O(N) 空间:O(1)
class Solution {
public int solve(int[] nums, int target) {
if(target==0)return 0;
if(nums==null||nums.length==0)return -1;
int res =nums.length+1;
int temp = 0;
int left = 0,right =nums.length-1;
for(int i=0;i<nums.length;i++){
temp+=nums[i];
if(temp>=target){
left = i;
break;
}
}··
if(temp<target)return -1;
if(temp==target){
res = Math.min(res,left+1);
}
while (left>=0){
temp -= nums[left--];
while (temp<target&&right>0){
temp+=nums[right--];
}
if(temp==target)res=Math.min(res,left+nums.length-right);
}
return res==nums.length+1?-1:res;
}
}
You are given a list of positive integers nums
and an integer target
. Consider an operation where we remove a number v
from either the front or the back of nums
and decrement target
by v
.
Return the minimum number of operations required to decrement target
to zero. If it's not possible, return -1
.
Constraints
n ≤ 100,000
where n
is the length of nums
import java.util.*;
class Solution {
public int solve(int[] nums, int target) {
int res = recursionSolve(nums, 0, nums.length - 1, target);
return res == Integer.MAX_VALUE ? -1 : res;
}
public int recursionSolve(int[] nums, int left, int right, int target){
if(target==0) return nums.length - (right - left + 1);
if(target<0) return Integer.MAX_VALUE;
if(left > right) return Integer.MAX_VALUE;
int leftTimes = recursionSolve(nums,left+1,right,target-nums[left]);
int rightTimes = recursionSolve(nums,left,right-1,target-nums[right]);
return Math.min(leftTimes,rightTimes);
}
}
public int solve(int[] nums, int target)
sum = sumOfNum - target = prefixSum[right] - prefixSum[left]
num中可能有若干子列满足和为sum
我们构造一个长度为N+1的前缀和数组predixSum[ N+1 ] (N为sumOfNum.length)
这样,predixSum[ right ] - predixSum[ left ] 表示数组nums中下标为left的数到下标为right - 1的数的和
我们固定 i = left(每回合i增加1),二分法不断寻找合适的mid,使得sum = sumOfNum - target = prefixSum[mid] - prefixSum[left]
一旦找到mid,它在原nums中对应着mid - 1的下标,从 i 到mid - 1有 (mid - 1 - i + 1)个元素,记为count个
然后我们用nums.length - count 就得到了移走了多少个元素,找到这个最小值就是我们的答案
public class Solution {
public int solve(int[] nums, int target) {
//sumOfNum - target = prefixSum[right] - prefixSum[left];
//sumOfNum - target = prefixSum[mid] - prefixSum[left];
int sumOfNum = 0;
for(int num : nums){
sumOfNum += num;
}
int sum = sumOfNum - target;
if(sum < 0) return -1;
int[] prefixSum = new int[nums.length + 1];
prefixSum[0] = 0;
//generate the prefixSum
for(int i = 1; i < prefixSum.length; i++){
prefixSum[i] = prefixSum[i-1] + nums[i-1];
}
int res = Integer.MAX_VALUE;
int cur = Integer.MAX_VALUE;
for(int i = 0; i <= nums.length; i++){
int left = i;
int right = nums.length;
while(left <= right){
int mid = (left + right) / 2;
if((prefixSum[mid] - prefixSum[i]) == sum){
cur = nums.length - (mid - i);
res = Math.min(cur,res);
break;
}
else if((prefixSum[mid] - prefixSum[i]) < sum){
//mid is smaller
left = mid + 1;
}
else{
//mid is larger
right = mid - 1;
}
}
}
return res == Integer.MAX_VALUE ? -1 : res;
}
public static void main(String[] args) {
int[] nums = new int[]{3,1,1,2,5,1,1};
int target = 7;
System.out.println(new Solution().solve(nums, target));
}
}
class Solution { public int solve(int[] nums, int target) { if(target==0)return 0; if(nums==null||nums.length==0)return -1; int res =nums.length+1; int temp = 0; int left = 0,right =nums.length-1; for(int i=0;i<nums.length;i++){ temp+=nums[i]; if(temp>=target){ left = i; break; } }·· if(temp<target)return -1; if(temp==target){ res = Math.min(res,left+1); } while (left>=0){ temp -= nums[left--]; while (temp<target&&right>0){ temp+=nums[right--]; } if(temp==target)res=Math.min(res,left+nums.length-right); } return res==nums.length+1?-1:res; } }
滑动窗口
diff = sum(nums) - target
,则可使用滑动窗口法,在nums中寻找总和等于diff
的最长窗口nums
的长度减去符合要求的最长窗口长度class Solution:
def solve(self, nums, target):
diff = sum(nums) - target
n = len(nums)
if diff < 0:
return -1
elif diff == 0:
return n
l, r, cnt = 0, 0, 0
res = 0
while r < n:
cnt += nums[r]
while cnt > diff:
cnt -= nums[l]
l += 1
if cnt == diff:
res = max(res, r - l + 1)
r += 1
return n - res if res > 0 else -1
Number of Operations to Decrement Target to Zero
思路
滑动窗口
代码
class Solution {
solve(nums, target) {
const n = nums.length;
let res = n + 1;
let l = 0;
let sum = 0;
let total = 0;
for (let num of nums) {
total += num;
};
for (let r = 0; r < n; r++) {
sum += nums[r];
while (sum > total - target) {
sum -= nums[l];
l++;
};
if (sum === total - target) res = Math.min(res, n - r + l - 1);
};
return res === n + 1 ? -1 : res;
};
}
复杂度分析
学到了 学到了 果然还是刷题刷的少,常见的思路也想不出来😂,转换思维,然后滑动窗口,跟昨天相比的是判断左边界是否收缩的判断条件需要注意下
import java.util.*;
class Solution {
public int solve(int[] nums, int target) {
int sum = 0;
for(int num:nums) sum += num;
if(target == sum)
return nums.length;
target = sum - target;
if(target < 0)
return -1;
int left = 0, right = 0, length = Integer.MIN_VALUE;
int window = 0;
while(right < nums.length) {
window += nums[right++];
while(window >= target) {
if(window == target && right - left > length) {
length = right - left;
}
window = window-nums[left++];
}
}
return length == Integer.MIN_VALUE ? -1: nums.length-length;
}
}
时间复杂度 O(n)
class Solution {
solve(nums, target) {
if(!nums.length&&!target) return 0;
let len = nums.length,
best = 0;
for (let i = 1; i < len; i++) nums[i] += nums[i - 1];
let y = nums[len - 1] - target;
if (y < 0) return -1;
if (y === 0) return len;
for (let i = -1, j = 0,l = 0; i < len - best && l <= target; l = nums[++i]) {
while (nums[j] - l < y) j++;
if (nums[j] - l === y) best = Math.max(best, j - i);
}
return best > 0 ? len - best : -1;
}
}
Number of Operations to Decrement Target to Zero
入选理由
暂无
题目地址
https://binarysearch.com/problems/Number-of-Operations-to-Decrement-Target-to-Zero
前置知识
题目描述
You are given a list of positive integers nums and an integer target. Consider an operation where we remove a number v from either the front or the back of nums and decrement target by v.
Return the minimum number of operations required to decrement target to zero. If it's not possible, return -1.
Constraints
n ≤ 100,000 where n is the length of nums Example 1 Input nums = [3, 1, 1, 2, 5, 1, 1] target = 7 Output 3 Explanation We can remove 1, 1 and 5 from the back to decrement target to zero.
Example 2 Input nums = [2, 4] target = 7 Output -1 Explanation There's no way to decrement target = 7 to zero.