算法刷题记录-双指针/滑动窗口(LeetCode)

news2024/12/28 19:56:37

809. Expressive Words

思路

根据题目描述,我们可以知道,如果要将某个单词定义为可扩张(stretchy),需要满足如下两个条件:

所以,我们在实现的时候,可以通过两个指针p1和p2,分别指向s和word,分别统计连续的相同字符数量c1和c2,然后再通过上述的两个条件进行判断,即:如果

(c1 != c2 && c1 < 3) || (c1 < c2 && c1 >= 3)

则表示该单词不是可扩张的。

代码

class Solution {
    public int expressiveWords(String s, String[] words) {
        int result = 0;
        char[] sc = s.toCharArray();
        for (String word: words) result += stretchyWord(sc, word.toCharArray()) ? 1 : 0;
        return result;
    }
    private boolean stretchyWord(char[] sc, char[] wc) {
        if (sc.length < wc.length) return false; // word的字符串长度不允许超过s的字符串长度
        int cp, p1 = 0, p2 = p1;
        while ((cp = p1) < sc.length && p2 < wc.length) {
            int c1 = 0, c2 = 0;
            while (p1 < sc.length && sc[p1] == sc[cp]) {
                c1++; p1++; // 在字符串s中,遍历连续的字符sc[cp]的数量
            }
            while (p2 < wc.length && wc[p2] == sc[cp]) {
                c2++; p2++; // 在字符串word中,遍历连续的的字符sc[cp]的数量
            }
            if ((c1 != c2 && c1 < 3) || (c1 < c2 && c1 >= 3)) return false;
        }
        return p1 == sc.length && p2 == wc.length; // 只有sc和wc都被遍历完毕,才返回true
    }
}

823. Binary Trees With Factors

思路

代码

class Solution {
    static final long MOD = (long) 1e9 + 7;
    public int numFactoredBinaryTrees(int[] arr) {
        Arrays.sort(arr);
        long[] ans=new long [arr.length];
        ans[0]=1;
        for (int i=1;i<arr.length;i++){
            ans[i]=1;
            int left=0;
            int right=i-1;
            while (left<=right){
                while (left<=right){
                    long prod= (long) arr[left] *arr[right];
                    if (prod==arr[i]){
                        break;
                    }
                    else if (prod<arr[i]){
                        left++;
                    }
                    else{
                        right--;
                    }
                }
                if (left>right){
                    break;
                }
                if (left==right){
                    ans[i]+=ans[left]*ans[left];
                }
                else{
                    ans[i]+=ans[left]*ans[right]*2;
                }
                left++;
                right--;
            }
            ans[i]%=MOD;
        }
        long final_ans=0;
        for (long val:ans){
            final_ans=final_ans+val;
            final_ans%=MOD;
        }
        return (int)final_ans;
    }
}

*828. Count Unique Characters of All Substrings of a Given String

思路 贡献法+双指针

请看下图,我们以s=“ABCD”为例,首先,可以将其拆分为10个子串(以“A”为基准的4个子串;以“B”为基准的3个子串;以“C”为基准的2个子串;以“D”为基准的1个子串;),那么由于s字符串中的字符都是彼此不重复的,所以,总结果其实就是“A”、“B”、“C”、“D”这个四个字符在所有10个子串中出现的次数之和,即:A出现4次 + B出现6次 + C出现6次 + D出现4次 = 20。

通过上面的例子,我们将问题转换为某个字符在子串中出现的个数问题了。那么,针对这个问题,其实有3种情况:

情况1:字符是“头元素”,那么出现次数可以通过:数组长度 - 元素下标位置 来计算出来。
情况2:字符是“尾元素”,那么出现次数可以通过:元素下标位置 - (-1) 来计算出来。
情况3:字符是“中间元素”,那么出现次数可以通过:(元素下标位置 - (-1)) * (数组长度 - 元素下标位置) 来计算出来。



那么前面我们是针对于字符串中字符不重复的情况来看的,下面我们再来看一下有重复字符的情况。其实,针对于这种情况,就产生了区间的概念。因为我们上面进行统计的时候,都是针对于某一区间内这个元素是唯一的,所以,如果发生了重复字符,我们就需要将其拆分为多个区间。以下图s="ABCB"为例,当我们要统计元素“B”的时候,由于发生了重复的情况,所以,我们要将其拆分为:
当B的下标=1的时候,它唯一的区间是[0,2] 当B的下标=3的时候,它唯一的区间是[2,3]
那么,由于产生了区间的概念,我们也随之创建两个指针,分别是head和tail,head指向的某区间开始位置的前一个位置;tail指向的是某区间结束为止的后一个位置。那么计算公式最终就是:(某元素下标位置 - head) * (tail - 某元素下标位置)。

我们得出了计算公式之后,就可以针对给出的字符串s中的每个字符进行遍历,在哈希表中记录一下每个元素的所在位置,key=字符,value=该字符出现的位置集合。具体实现,请参照:代码1-哈希表采用哈希表方式实现。如果需要提升执行效率,我们也可以采用数组来记录每个元素的所在位置,26个字母对应数组的坐标,然后一个数组是用来针对某个元素出现多次进行统计

解题思路我们就说完了。下面我们以s=“LEETCODE”为例,看一下具体的计算过程。由于下图中的计算细节已经在图中写出来了,所以这里的文字部分就不去赘述了。具体的计算过程,请参见下图。
在这里插入图片描述

代码1-哈希表

    public int uniqueLetterString(String s) {
        HashMap<Character, ArrayList<Integer>> map = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            if (!map.containsKey(s.charAt(i))) {
                map.put(s.charAt(i), new ArrayList<>());
            }
            map.get(s.charAt(i)).add(i);
        }
        int ans = 0;
        for (var pair : map.entrySet()) {
            int head = -1;
            int tail = -1;
            var items = pair.getValue();
            for (int i = 0; i < items.size(); i++) {
                tail = i < (items.size() - 1) ? items.get(i + 1) : s.length();
                ans += (items.get(i) - head) * (tail - items.get(i));
                head = items.get(i);
            }
        }
        return ans;
    }

849. Maximize Distance to Closest Person

思路(双指针+贪心)

我们考虑前一个1出现的位置prev,一直向右遍历的位置i每当seats[i]为1时,iprev相减的值即为距离,求所有可能的距离的最大值即可。注意,在实现代码中,考虑的略复杂了一些 其中while(seat[i]==0)的部分可优化为prev=-1。但是,我们一定需要当遍历结束后强制判断一次,因为可能出现类似 [ 1 , 0 , 0 , 0 ] [1,0,0,0] [1,0,0,0]此类序列。

代码

    int maxDistToClosest(vector<int>& seats) {
        int prev;
        int i=0;
        while (seats[i]==0){
            i++;
        }
        prev=i;
        int max_length=i;
        for (i++; i < seats.size(); ++i) {
            if (seats[i]==0){
                continue;
            }
            int length=i-prev-1;
            max_length=max((int)ceil((double)length/2),max_length) ;
            prev=i;
        }
        int length=seats.size()-prev-1;
        if (length>max_length){
            max_length=length;
        }
        return max_length;
    }

881. Boats to Save People

思路

首先对数组进行排序,设置两个指针leftright。令每次救生艇乘坐的人重量最大。若left+right>limit,则说明位于right位置的人需要一个独立的救生艇。当左右指针相遇时,说明剩下需要一个独立的救生艇,再次+1。

代码

class Solution {
    public int numRescueBoats(int[] people, int limit) {
        int ans=0;
        Arrays.sort(people);
        int left=0;
        int right=people.length-1;
        while (left<=right){
            while (right>left&&people[left]+people[right]>limit){
                right--;
                ans++;
            }
            if (left==right){
                ans++;
                break;
            }
            ans++;
            left++;
            right--;
        }
        return ans;
    }
}

904. Fruit Into Baskets

思路 双指针+HashMap

构建一个HashMap,令left指针标注序列开始点,right指针标注序列结束点。
每次将一个新水果fruits[right]加入序列,若map的长度大于2,则右移left指针并对map内的fruits[left]进行-1操作,若map[fruit[left]]为0,则表示已完全移除,map长度减一。从此往复,统计map内key的value和的最大值。

代码

    public int totalFruit(int[] fruits) {
        HashMap<Integer, Integer> map = new HashMap<>();
        int left = 0;
        int right = 0;
        int ans=0;
        while (right < fruits.length) {
            map.merge(fruits[right], 1, Integer::sum);
            while (map.size() > 2) {
                map.merge(fruits[left], -1, Integer::sum);
                if (map.get(fruits[left])==0){
                    map.remove(fruits[left]);
                }
                left++;
            }
            int curr_ans=0;
            for (var key:map.keySet()){
                curr_ans+=map.get(key);
            }
            ans=Math.max(ans,curr_ans);
            right++;
        }
        return ans;
    }

2841. Maximum Sum of Almost Unique Subarray

思路 滑动窗口

用滑动窗口枚举长为 k 的子数组,用哈希表记录子数组中各元素出现的次数,以维护当前子数组中不同元素的个数

代码

class Solution {
    public long maxSum(List<Integer> nums, int m, int k) {
        HashMap<Integer,Integer>map=new HashMap<>();
        int left=0;
        int right=k;
        long ans=0;
        long curr_sum=0;
        for (int i=0;i<k;i++){
            curr_sum+=nums.get(i);
            map.merge(nums.get(i),1,Integer::sum);
        }
        if (map.size()>=m){
            ans=Math.max(curr_sum,ans);
        }
        while (right<nums.size()){
            curr_sum+= nums.get(right);
            curr_sum-= nums.get(left);
            map.merge(nums.get(right),1,Integer::sum);
            map.merge(nums.get(left),-1,Integer::sum);
            if(map.get(nums.get(left))==0){
                map.remove(nums.get(left));
            }
            if (map.size()>=m){
                ans=Math.max(curr_sum,ans);
            }
            left++;
            right++;

        }
        return ans;
    }

}

2844. Minimum Operations to Make a Special Number

思路 滑动窗口

要想被25整除,末尾数字只能是00255075 。只要从最后一个数字遍历即可,若最后一位数字为5,则向前寻找2或者7、否则向前寻找0或者5。

代码

class Solution {
    public int minimumOperations(String _num) {
        char[] num=_num.toCharArray();
        int ans=120;
        boolean containsZero=false;
        int end=num.length-1;
        while (end>0){
            if (num[end]=='0'||num[end]=='5'){
                int prev=end-1;
                if (num[end]=='0'){
                    containsZero=true;
                    while (prev>=0&&(num[prev]!='5'&&num[prev]!='0')){
                        prev--;
                    }
                }
                else {
                    while (prev>=0&&(num[prev]!='2'&&num[prev]!='7')){
                        prev--;
                    }
                }
                if (prev>=0){
                    ans=Math.min(ans,end-prev-2+num.length-end);
                }
            }
            end--;
        }
        if (ans==120){
            return containsZero? num.length-1 :num.length ;
        }
        return ans;
    }
}

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

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

相关文章

Reactor模型深度解析

文章目录 Reactor模型深度解析什么是Reactor模型Reactor模型的优势Reactor模型的实现方式同步IO异步IOselectpollepoll Reactor模型的应用场景总结 Reactor模型深度解析 什么是Reactor模型 Reactor模型是一种高并发IO编程模型&#xff0c;它的主要目的是简化IO编程的复杂性&a…

安装Python虚拟环境

环境 python3.10 Ubuntu22.04 首先设置默认python #查看python3 的安装位置 which python3 #设置默认python为 python3 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1 #查看是否成功 python --version创建虚拟环境 #安装venv sudo apt i…

【韩顺平】Linux基础

1.网络连接三种方式 1.1 桥接模式&#xff1a;虚拟系统可以和外部系统通讯&#xff0c;但是容易造成IP冲突【1-225】 1.2 NAT模式&#xff1a;网络地址转换模式。虚拟系统可以和外部系统通讯&#xff0c;不造成IP冲突。 1.3 主机模式&#xff1a;独立的系统。 2.虚拟机克隆 3…

Outlook无需API开发连接钉钉群机器人,实现新增会议日程自动发送群消息通知

Outlook用户使用场景&#xff1a; 在企业中&#xff0c;会议和活动的顺利举行对于业务运转和团队协作至关重要。然而&#xff0c;计划的变动总是无法避免&#xff0c;这可能会导致其他人的计划受到影响&#xff0c;打乱原有的安排。为了解决这个问题&#xff0c;许多企业开始使…

Leetcode131. 分割回文串

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 题解&#xff1a;力扣&#xff08…

xargs如何保留文本中的引号

如果文本中有引号&#xff0c;直接用xargs管道操作的话&#xff0c;引号会丢失&#xff0c;如下 该如何保留每一行文本中的引号呢&#xff0c;需要用到xargs的-d选项&#xff0c;设置一个分隔符&#xff0c;这里可以选用换行符来分割 顺便多来一条&#xff0c;直接将文本参数作…

亚马逊秋季促销指南——如何更好的利用促销?

最新消息&#xff0c;亚马逊官方宣布将会在10月份举行Prime会员大促&#xff0c;覆盖多个站点&#xff0c;亚马逊卖家们一定要抓住这波促销机会&#xff0c;在这个秋季再冲一把&#xff01;但是还有一些小白玩家可能对于亚马逊促销了解不够&#xff0c;那么接下来我要讲的这些准…

无涯教程-JavaScript - HEX2OCT函数

描述 HEX2OCT函数将十六进制数转换为八进制数。 语法 HEX2OCT (number, [places])争论 Argument描述Required/Optionalnumber 您要转换的十六进制数。 数字不能超过10个字符(40位)。数字的最高有效位是符号位。其余的39位是幅度位。 负数使用二进制补码表示。 Requiredpla…

微调chatGLM-6B大模型的方法

GLM官方的知乎微调教程&#xff1a;https://zhuanlan.zhihu.com/p/618498001 GLM官方的GitHub微调教程&#xff1a;https://github.com/THUDM/ChatGLM-6B/tree/main/ptuning 说这个微调出的模型和原模型是同时加载的&#xff0c;输入文本的时候会先看看微调出的模型有没有存相应…

服务器分析和监控

在当今数字化时代&#xff0c;对于网络流量的分析和监控变得越来越重要。本文将详细介绍如何利用HTTPS代理服务器来实现高效、安全且可靠的流量分析与监控功能&#xff0c;并提供具体操作步骤以及相关技巧。无论是企业需要优化网络性能还是个人用户&#xff0c;在遵循法规合规前…

E810 100G网卡和pcie bridge 总线带宽协商期望x16,结果X1,导致vpp性能不及预期

现象&#xff1a;pktgen 发包10000M/pps&#xff0c;vpp 运行在1&#xff0c;2&#xff0c;4&#xff0c;8&#xff0c;16 worker数时&#xff0c;数据包size&#xff08;64&#xff0c;256&#xff0c;512&#xff09;数据包转发量没有期望的差距量&#xff0c;且vpp接口rx-mi…

索尼 toio™应用创意开发征文|toio俄罗斯方块游戏

目录 引言 摘要 创意简述 准备工作&#xff5c;手工开始 代码编写&#xff5c;合理集成 使用体验&#xff5c;近乎奇妙 引言 索尼toio™编程机器人是一款引领技术创新的产品&#xff0c;为开发者提供了一个全新的编程和创造平台。toio™的设计旨在将技术、塑性和乐趣融为…

SV-6002T-P 网络对讲求助终端,立柱式智慧城市网络对讲求助终端,停车场出入口一键求助终端

SV-6002T-P 网络对讲求助终端&#xff0c;立柱式智慧城市网络对讲求助终端&#xff0c;停车场出入口一键求助终端 描述&#xff1a;SV-6002T是深圳锐科达电子有限公司的一款新型立柱型室外防水一键求助对讲终端&#xff0c;具有10/100M以太网接口&#xff0c;其接收网络的音频数…

全球研发中心城市专题协商会课题调研组莅临麒麟信安考察指导

9月7日上午&#xff0c;长沙市政协党组副书记、副主席石长松&#xff0c;市委统战部副部长、市工商联党组书记何惠风&#xff0c;市政协研究室主任郑志华&#xff0c;市工商联党组成员、副主席王婧等领导一行莅临麒麟信安开展全球研发中心城市专题协商会课题调研&#xff0c;麒…

由于 SIGPROF 信号,clone() 系统调用无限重启

最近遇到一个c 代码里调用system函数然后没返回的问题&#xff0c;此时调用进程所在CPU占用率100%。 通过 strace 和ftrace工具跟踪系统调用&#xff0c;以及查看内核源码&#xff0c;发现 此时&#xff0c;进程会一直不停的调用 clone系统调用&#xff0c;而 clone系统调用一…

Java项目-苍穹外卖-Day10-SpirngTask及WebSocket

文章目录 前言SpringTask介绍SpringTask_corn表达式Spring_Task入门案例 订单状态定时处理需求分析代码开发功能测试 前言 本章实现的业务功能 超时未支付订单自动取消&#xff0c;配送中订单商家忘点完成自动再固定时间检查且修改成完成状态 来单提醒功能 催单提醒功能 …

什么牌子的灯具性价比高?好用实惠的护眼台灯品牌推荐

现在我们很多家长对自己孩子的视力十分关心&#xff0c;生怕自己的孩子是近视、远视、弱视等等。对于父母而言&#xff0c;在孩子读书压力大课业重的关键时期&#xff0c;为孩子选择合适的桌椅&#xff0c;保护灯具从而保护孩子的眼睛是非常重要的事情!那么买给孩子读书做功课的…

iTOP-RK3568开发板内核模块实验-设置交叉编译器

在上一章节我们编写了最简单的 helloworld 驱动程序。有了驱动程序以后&#xff0c;要如何编译并使用驱动呢。编译驱动有俩种方法&#xff0c;分别是将驱动编译成内核和将驱动编译成内核模块。我们先来学习如何将驱动编译成内核模块、 4.1 设置交叉编译器 1 下载网盘资料下的…

U盘格式化后数据恢复?别担心,2个方法轻松恢复!

“昨天我的u盘好像中病毒了&#xff0c;为了清除里面的病毒&#xff0c;我不得已将u盘进行了格式化操作。但是&#xff0c;我的u盘中很重要的文件也被删除了&#xff01;这可怎么办啊&#xff1f;还有恢复的机会吗” 平常在使用u盘时&#xff0c;我们可能会因为各种原因&#x…

【漏洞复现】金盘图书馆微信管理后台 getsysteminfo 未授权访问漏洞

漏洞描述 北京金盘鹏图软件技术有限公司的金盘图书馆微信管理后台 getsysteminfo 存在未授权访问漏洞,可获取管理员账号密码等敏感数据&#xff0c;导致攻击者能以管理员身份进入系统窃取敏感信息和危险操作。 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络…