Leetcode刷题笔记4

news2024/12/24 2:09:35

1658. 将 x 减到 0 的最小操作数

1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode)

示例 3:

输入:nums = [3,2,20,1,1,3], x = 10
输出:5
解释:最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。

如果想直接找到这些元素是比较困难的,所以:

正难则反

找到两个区域,a在左边,b在右边是的a + b = x。
[[    ]        [     ]]
   a             b
创建一个sum,sum是整个数组的和
这时可以考虑中间的这个区域,使得sum - x,使中间这块连续的区域最长

转化:找出最长的子数组的长度,所有元素的和正好等于sum - x
                                            len                                           target
n - len

解法一:暴力枚举

target = sum - x
  [ < target   ] R(>=target)
[                  ] ]             ]
  L

sum1 来标记L和R所指的区域的和
让R依次向后移动找那个最佳的位置

如果R找到一个元素使得前面的和 >= target,那么那个元素之前的元素之和肯定 < target

暴力解法的话,就让L右移一步,然后R回到L这里
但是R还有必要向左移动吗?
其实没有必要,本身前面的区域就小于target了,这时删除了第一个元素肯定还是小于target
所以R没有必要回去,所以让R要么原地不动,要么向后移动

解法二:滑动窗口

1.left = 0,right = 0

2.进窗口 -> sum1 += nums[right]

3.判断 -> 当这段区域的和 > target 就出窗口
出窗口 -> sum1 -= nums[left]

更新结果 -> 如果这段区域的和 = target 再更新结果

最后再用n减一下,得出最后结果

时间复杂度:O(N)
空间复杂度:O(1)

代码:C++

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int sum = 0; // 整个数组的和

        for(int a : nums) sum += a; // 把里面每个数都拿出来然后+=
        int target = sum - x;

        // 细节问题
        if(target < 0) return -1;

        int ret = -1; // 如果没有找到结果,返回-1,所以直接赋值-1
        for(int left=0, right=0, tmp=0; right < nums.size(); right++)
        {
            // 进窗口
            tmp += nums[right];

            while(tmp > target) // 判断
        {
            tmp -= nums[left++]; // 出窗口
        }
        if(tmp == target) // 更新结果
        {
            ret = max(ret, right - left + 1);
        }
        }
        if(ret == -1) return ret;
        else return nums.size() - ret;
    }
};

904. 水果成篮

904. 水果成篮 - 力扣(LeetCode)

等于是连续摘

转化:找出一个最长的子数组长度,子数组中不超过两种类型的水果

fruits = [1,2,3,2,2]

解法一:暴力枚举 + 哈希表

[1,2,3,2,2]

比如固定1,那就只能找到1,2
如果固定2,可以采摘到2,3,2,2
...
找出所有可能性,然后选择最长的

可以借助哈希表储存水果类型,统计水果一共出现多少种

解法二:滑动窗口

比如:
      R
f = [1, 2, 1, 2, 3, 2, 3, 3]
      L
hash<int,int> 不仅要存入水果的种类,还要存入水果的数量
1. left = 0,right = 0

2. 进窗口 -> hash[f[Right]]++

3. 判断 -> hash.size > 2
出窗口 -> hash[f[Left]]--,要判断一下,如果对应的位置的元素变成0,要从哈希表中删除

更新结果

代码:C++

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        unordered_map<int, int> hash; // 统计窗口内出现了多少种水果

        int ret = 0;
        for(int left = 0, right = 0; right < fruits.size(); right++)
        {
            hash[fruits[right]]++; // 进窗口

            while(hash.size() > 2) // 判断
            {
                hash[fruits[left]]--; // 出窗口
                if(hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]); // 变成0就从哈希表中删除
                }
                left++;
            }
            ret = max(ret, right - left + 1); // 结果应该是left和right所指区间的长度
        }
        return ret;
    }
};

时间复杂度比较耗时,所以可以对哈希表做一个优化
 

// 优化后:
// 因为
//1 <= fruits.length <= 10^5
//0 <= fruits[i] < fruits.length
//所以可以使用一个数组来代表哈希表

int hash[100001] = {0};
//
for (int left = 0, right = 0, kinds = 0; right < fruits.size(); right++)
if(hash[fruits[right]] == 0) kinds++; // 维护水果的种类
while (kinds > 2)
hash.erase(fruits[left]); -> if(hash[fruits[left]] == 0) kinds--;

// 如果数据范围是有限的,可以使用数组来替代哈希表,比直接使用容器效率的提升很大

438. 找到字符串中所有字母异位词

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

1. 暴力解法

1. 如何快速判断两个字符串是否是“异位词”
s1 = "aabca"
s2 = "abaca"

用排序然后再一一比较的方法太耗时了

所以可以利用哈希表
遍历s1的字符,把字符依次丢到hash1
遍历s2的字符,把字符依次丢到hash2
然后比较两个哈希表中对应位置字符出现的个数是否相等,相等就是异位词

2.解决问题
比如:
s = "cbaebabacd" 
以c为起点,找一个长度为m的子串,
把子串里面每个字符出现的个数丢到另一个哈希表hash2里面
然后遍历完这个子串之后,比较一下这两个哈希表是否相等就可以
然后以b为起点...

p = "abc",长度为m,hash1

hash1统计p里面的个数
hash2统计滑动窗口里面每个字符出现的个数

如何优化呢

每次枚举的时候,只需要把第一个字符删除,然后添加下一个字符就可以了
所以没有必要重新从头开始统计信息

s = "c b a e b a b a c d"
       L    R
s = "c b a e b a b a c d"
          L    R


解法:滑动窗口 + 哈希表

1. left = 0, right = 0

2. 进窗口 -> hash2[in]++

3. 判断 -> right - left + 1 > m,就移动
出窗口 -> hash2[out]--

更新结果 -> check(hash2, hash1)

优化:可以对更新结果的判断条件(check)进行优化
利用变量count来统计窗口中“有效字符”的个数

s = "ccbaebabacd",hash2

p = "abc",hash1: a -> 1, b -> 1, c -> 1

进窗口:进入后 -> 判断此时hash2[in]是否小于等于hash1[in]
如果小于等于,就是添加的有效字符,count++
如果是其余情况,就是无效字符,count不变

出窗口:出去前 -> hash2[out] <= hash1[out] -> count--
其余情况count不变

更新结果:count == m

代码:C++

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int hash1[26] = { 0 }; // 统计字符串p中每个字符出现的个数

        for(auto ch : p) hash1[ch - 'a']++; // ch - 'a'对应位置的下标

        int hash2[26] = { 0 }; // 统计窗口里面每一个字符出现的个数
        int m = p.size();
        for(int left=0, right=0, count=0; right < s.size(); right++)
        {
            char in = s[right];
            //hash2[in - 'a']++; // 进窗口
            // 维护一下count,可以在hash2前面添加++
            if(++hash2[in - 'a'] <= hash1[in - 'a']) count++; // 进窗口+维护

            if(right - left + 1 > m) // 判断
            {
                char out = s[left++]; // 元素搞出去之后,left向右移动一步
                if(hash2[out - 'a']-- <= hash1[out - 'a']) count--; // 出窗口 + 出去前维护count
                //hash2[out - 'a']--; // 出窗口
            }
            // 更新结果
            if(count == m) ret.push_back(left);
        }
        return ret;
    }
};

30. 串联所有单词的子串

30. 串联所有单词的子串 - 力扣(LeetCode)

s = "barfoothefoobarman", words = ["foo","bar"] words里面的字符串长度都为3

s = "[bar][foo][the][foo][bar][man]"
          b     a     c     a      b     d

跟438. 找出所有字母的异位词 很像

滑动窗口 + 哈希表

不同之处:
1. 哈希表
hash<string, int> -> string对应字符,int对应字符串出现的次数

2. left与right指针的移动
移动的步长,是给定字符串里面每个单词的长度(len)

3. 滑动窗口执行的次数
len

代码:C++

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string, int> hash1; // 保存words 里面所有单词的频次

        for(auto& s: words) hash1[s]++; // 遍历字符串数组

        vector<int> ret;
        int len = words[0].size(), m = words.size();
        for(int i = 0; i<len; i++) // 执行len次
        {
            // 这个哈希表维护滑动窗口内面单词的频次
            unordered_map<string, int> hash2;
            for(int left=i, right=i, count=0; right + len <= s.size(); right+=len) // 因为是要把后面的字符串放到滑动窗口里面,如果right太靠后,后面根本就没有长度为len的字符串
            {
                // 进窗口 + 维护count
                string in = s.substr(right,len);
                hash2[in]++;
                // 第一个哈希表不一定有这个单词,这样的话就会重新创建一个in,丢到哈希表
                // 所以会有时间消耗
                // 如果in出现在第一个哈希表里面的时候才接下来再判断
                // 因为此时判断的时候这个in一定是在里面了,所以就不用重新再创建一个in在哈希表里面了
                if(hash1.count(in) && hash2[in] <= hash1[in]) count++; // 可以提前判断一下,节省时间
                // 判断
                if(right - left + 1 > len * m) // len * m 窗口里面所有字符串的长度
                {
                   // 出窗口 + 维护count
                   string out = s.substr(left, len);
                   if(hash1.count(out) && hash2[out] <= hash1[out]) count--; // 有效单词
                   hash2[out]--;
                   // 出窗口后,left向后移动len步
                   left += len;
                }

                // 更新结果,当有效字符的个数正好等于字典里面单词的个数时
                if(count == m) ret.push_back(left);
            }
        }
        return ret;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1693633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.2k star的万能视频解析下载插件

今天给大家介绍一个超级厉害的浏览器插件&#xff0c;可以解析各个平台网页视频——猫抓。 项目简介 猫抓&#xff08;cat-catch&#xff09; 是一款资源嗅探扩展插件&#xff0c;他能够帮助你筛选列出当前页面的资源。简单来说&#xff0c;当你打开任意一个带有视频的网页&a…

分享几张漂亮的linux kde主题

分享几张漂亮的linux kde主题&#xff1a;在系统设置的全局主题内下载。

Git Core Lecture

1、Git 简介 官方介绍&#xff1a;Git is a fast distributed revision control system (Git 是一个快速的分布式版本控制系统) 2、Git Core Command 2.1 git init git 工程初始化&#xff0c;会在工作区 (working directory) 根目录中创建.git 目录 # 创建目录 $ mkdir git-i…

node.js —— 解读http模块

目录 http模块&#xff1a; http模块的引入&#xff1a; 创建web服务器的基本步骤&#xff1a; web服务器的一些基本属性&#xff1a; 上述知识汇总案例&#xff1a; http模块&#xff1a; http模块的引入&#xff1a; const http require (http) 创建web服务器的基本步骤…

数据可视化每周挑战——全国星巴克门店数据可视化

这是我国星巴克门店的位置&#xff0c;营业时间等数据。 1.导入需要用的库&#xff0c;同时设置绘图时用到的字体&#xff0c;同时防止绘图时负号无法正常显示的情况。 import pandas as pd from pyecharts.charts import Bar,Map,Line,Pie,Geo from pyecharts import option…

iBarcoder for Mac v3.15.1中文激活版:让条形码生成变得如此简单

在现代社会&#xff0c;条形码无处不在&#xff0c;从超市商品到物流包裹&#xff0c;都离不开它的身影。iBarcoder for Mac作为一款简单易用的条形码生成软件&#xff0c;让条形码的生成变得如此简单。 iBarcoder for Mac v3.15.1中文激活版下载 无论你是需要为商品添加条形码…

springboot打包目录解析

一、引言 Java开发中我们使用最多的便是spring框架&#xff0c;比如springboot应用。微服务模式下&#xff0c;每个服务都是一个springboot应用&#xff0c;都会被打包成一个可执行jar包。那么我们有多少人尝试去了解过这个可执行jar到底是什么&#xff1f;它的结构是什么样的…

论文阅读--CLIPasso

让计算机把真实图片抽象成简笔画&#xff0c;这个任务很有挑战性&#xff0c;需要模型捕获最本质的特征 以往的工作是找了素描的数据集&#xff0c;而且抽象程度不够高&#xff0c;笔画是固定好的&#xff0c;素描对象的种类不多&#xff0c;使得最后模型的效果十分受限 之所以…

算法之背包问题

可分的背包问题是可以用贪心法来解决&#xff0c;而0-1背包问题通常使用动态规划方法来解决。 可分背包问题&#xff1a; 在可分背包问题中&#xff0c;物品可以被分割&#xff0c;您可以取走物品的一部分以适应背包的容量。这里的关键是物品的价值密度&#xff0c;即单…

GNSS中的多路径效应原理及计算方法

1 多路径效应原理 图1 多路径效应原理图 2 计算方法 如需原文&#xff0c;可加多源融合定位与智能控制讨论群获取,QQ群号&#xff1a;51885949

JAVAEE之线程(10)_线程池、线程池的创建、实现线程池

一 线程池 1.1为什么要有线程池&#xff1f; 线程池顾名思义是由多个线程所组成&#xff0c;作用就是减少线程的建立与销毁&#xff0c;与数据库连接池相同概念&#xff0c;为了减少连接与释放&#xff0c;从而降低消耗提升效率。 1.2 线程池的优势 总体来说&#xff0c;线程…

Milvus Cloud 非结构化数据平台

从技术面来看,向量数据库底座自然而然向外延伸的产品包含: 1)向量提取,从非结构化数据中提取向量,这是向量数据库上游的工作,十分重要; 2)模型选择,选择正确的模型,能够更精准、更高质量地提取向量; 3)映射管理,即管理数据的本体和数据的语义层之间的映射,在…

设计模式之创建型模式---原型模式(ProtoType)

文章目录 概述类图原型模式优缺点优点缺点 代码实现 概述 在有些系统中&#xff0c;往往会存在大量相同或者是相似的对象&#xff0c;比如一个围棋或者象棋程序中的旗子&#xff0c;这些旗子外形都差不多&#xff0c;只是演示或者是上面刻的内容不一样&#xff0c;若此时使用传…

【spring】@RequestBody注解学习

RequestBody介绍 RequestBody 是 Spring Framework 中的一个注解&#xff0c;用于将 HTTP 请求的正文绑定到处理方法的参数上。这个注解通常用于处理 POST 或 PUT 请求&#xff0c;这些请求通常包含 JSON 或 XML 格式的数据。 RequestBody 将 HTTP 请求的正文内容转换成指定的…

前端vue项目遇到的问题01——那些初级问题

前端vue项目遇到的问题01——那些初级问题 1. npm install 问题1.1 依赖冲突1.1.1 详细问题1.1.2 报错原因1.1.3 解决问题1.1.3.1 方式1——无视冲突1.1.3.1 方式2——更换依赖版本 1.2 nodejs版本问题1.3 node版本正确的情况&#xff08;audit问题&#xff09;&#xff08;这个…

OpenH264 编解码器介绍

思科 思科系统&#xff08;英语&#xff1a;Cisco Systems, Inc.&#xff09;是一间跨国际综合技术企业&#xff0c;总部设于加州硅谷&#xff1b;思科开发、制作和售卖网络硬件、软件、通信设备等高科技产品及服务&#xff0c;并透过子公司&#xff08;例子有OpenDNS、Webex、…

【C语言】整型提升与char取值范围

整型提升介绍 C语言中整型算术运算总是至少以缺省&#xff08;默认&#xff09;整型类型的精度来进行的。为了获得这个精度&#xff0c;表达式中字符、短整型操作数在使用前被转换为普通整型。而这个过程是悄悄发生的。 整型提升的意义&#xff1a; 表达式的整型运算要在CPU…

小米财报:业绩远超预期,汽车推着手机跑!

随着一季度财报陆续出炉&#xff0c;企业间的分化越来越明显。 新环境下&#xff0c;很多公司都陷入停滞时&#xff0c;去讨论“掉队”已经没有多少意义&#xff0c;现在真正值得我们关注的&#xff0c;是那些在逆风情况下&#xff0c;还能“领先”的企业。毫无疑问&#xff0…

小程序主体变更是通过迁移吗?是需要2个小程序吗?

小程序迁移变更主体有什么作用&#xff1f;好多朋友都想做小程序迁移变更主体&#xff0c;但是又不太清楚具体有啥用&#xff0c;今天我就来详细说说。首先&#xff0c;小程序迁移变更主体最重要的作用就是可以修改主体。比如你的小程序原来是 A 公司的&#xff0c;现在 A 公司…