力扣刷题笔记2023.1.7和1.8

文章讨论了力扣每日一题中的一个问题,即如何通过移除数组元素将给定数值x减到0,最小操作数是多少。分析了两种解题方法,一种是DFS深度优先遍历,但由于时间复杂度高可能超时;另一种是滑动窗口方法,具有线性时间复杂度,是更优的解决方案。
摘要由CSDN通过智能技术生成

力扣刷题笔记

力扣每日一题1.7将x减到0的最小操作数
力扣每日一题1.8统计包含给定前缀的字符串



前言

力扣每日一题(将x减到0的最小操作数),从题目分析到各种解决办法
题目:

给你一个整数数组nums和一个整数x。每一次操作时,你应当移除数组最左边或最右边的元素,然后从x中减去该元素的值。请注意,需要修改数组以供接下来的操作使用。
如果可以将x恰好减为0,返回最小操作数;否则,返回-1。


一、题目分析

本题主要就是在减的过程中做出选择,到底是选择数组最左边的元素还是最右边的元素,并判断是否可以减为0,因此其实可以把其抽象成二叉树的数据结构,即到底是选左边还是选右边。并最后比较每一个减为0的操作数,选出最小的操作数并返回。

二、解题方法

method1:dfs深度优先遍历,

此算法时间复杂度爆炸,在最坏情况下,即减去数组里的所有元素才可为0的情况,算法时间复杂度达到O(2^n),达到指数复杂度(因为每次可以有两个选择,需要选择n次,且后一次是在前一次的基础上做选择)因此该算法时间复杂度为指数级,会超过时间限制。

代码如下(示例):

class Solution {
private:
    int minOperation = INT_MAX;
public:

    void dfs(vector<int>& nums,int leftPtr,int rightPtr,int finalX,int operation){
       // cout << "leftPtr: " << leftPtr << " rightPtr: " << rightPtr << " finalX: " << finalX << endl; 
       if(finalX < 0){
           return;
       }
        if(leftPtr > rightPtr){
            if(finalX == 0){
                minOperation = min(minOperation,operation);
            }
            return;
        }
        if(finalX == 0){
            minOperation = min(minOperation,operation);
            return;
        }
        dfs(nums,leftPtr+1,rightPtr,finalX - nums[leftPtr],operation+1);
        dfs(nums,leftPtr,rightPtr-1,finalX - nums[rightPtr],operation+1);
    }
    int minOperations(vector<int>& nums, int x) {
        dfs(nums,0,nums.size()-1,x,0);
        if(minOperation == INT_MAX){
            return -1;
        }
        return minOperation;
    }   
};

method2:滑动窗口

本题其实可以理解为该数组的某一个前缀和某一个后缀元素之和为x,取操作数最少。
与method1一样,标记两个指针下标,leftPtr和rightPtr,leftPtr代表删除下标小于等于leftPtr的元素值,即取下标小于等于leftPtr的数组元素前缀;rightPtr代表删除下标大于等于rightPtr的元素,即取下标大于等于rightPtr的元素为后缀。
注意初条件的设置,初始时leftPtr为-1,rightPtr为0,即数组全部元素作为后缀,取和。

  • 若初始条件的和小于x,即无论怎么样都不可能满足题目要求,返回-1;
  • 若初始条件的和等于x,则只有全部删除元素(从前往后或从后往前删操作数一样),才可以满足题目要求
  • 若初始条件的和大于x,则移动rightPtr,可减少后缀的和。
  • 最后再在外部包一个循环,即移动leftPtr,增加前缀和,存储前缀和+后缀和 = x的最小操作数。
    注意:在本代码中未详细规定leftPtr<=rightPtr(逻辑上应该是要规定的),但其实隐含着leftPtr<=rightPtr,因为若能进循环代表数组之和一定大于等于x,此时若leftPtr > rightPtr,则前缀和+后缀和一定大于x(有重复元素),因此rightptr++,直到rightPtr>=leftPtr才可继续循环下去
    代码如下(示例):
class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int size = nums.size();
        int res = size + 1;
        int leftPtr = -1,rightPtr = 0,leftSum = 0,rightSum = 0;
        for(int i = 0;i < size;i++){
            rightSum += nums[i];
        }
        if(rightSum < x){
            return -1;
        }
        for(;leftPtr < size;leftPtr++){
            
            if(leftPtr != -1){
                leftSum += nums[leftPtr];
            }
            while(leftSum + rightSum > x && rightPtr < size){
                
                rightSum -= nums[rightPtr];
                //cout << "jhaskdk" << leftPtr << " " << rightPtr << endl;
                rightPtr++;
            }
            if(leftSum + rightSum == x){
                res = min(res,leftPtr + 1 + size - rightPtr);
            }
        }
        return res == size + 1? -1 : res;
    }
};

该方法的时间复杂度为0(n),leftPtr由0遍历到size-1,空间复杂度为O(1)

每日一题1.8(统计包含给定前缀的字符串easy)

题目描述:
给定一个字符串数组words和一个字符串pref。返回words中以pref作为前缀的字符串的数目,字符串s的前缀就是s的任一前缀连续字符串。
暴力解决即可:

class Solution {
public:
    bool isPrefString(string word,string pref){
        int size1 = word.size();
        int size2 = pref.size();
        if(size1 < size2){
            return false;
        }
        for(int i = 0;i < size2;i++){
            if(word[i] != pref[i]){
                return false;
            }
        }
        return true;
    }
    int prefixCount(vector<string>& words, string pref) {
        int res = 0;
        for(string word : words){
            if(isPrefString(word,pref)){
                res++;
            }
        }
        return res;
    }
};

总结

本题是用滑动窗口解决的题目,滑动窗口太久没做,不太熟悉,后面需要进一步巩固加强。(method1太傻)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值