LeetCode HOT100(二)双指针

移动0

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]


解法1:双指针+交换
指针L:维护一个非零序列,L之前的元素都是非零的元素
指针R:寻找非零的元素,将其加入到L维护的序列中

public void moveZeroes(int[] nums) {
    int l = 0;
    int r = 0;
    while(r<nums.length){
        if(nums[r]!=0)
            swap(nums,l++,r);
        r++;
    }
}

public void swap(int[] nums,int l,int r){
    if(l == r) return;
    nums[l] = nums[l] ^ nums[r];
    nums[r] = nums[l] ^ nums[r];
    nums[l] = nums[l] ^ nums[r];
}
func moveZeroes(nums []int)  {
    slow := 0
    for i,_ := range nums{
        if nums[i]!=0{
            tmp := nums[slow]
            nums[slow] = nums[i]
            nums[i] = tmp
            slow++
        }
    }
}

解法2:双指针+赋值0
解法和1类似,只不过1是交换非零元素和0元素,2将非零元素全部移动到前面,后面统一赋值为0

public void moveZeroes(int[] nums) {
    int cur = 0;
    for(int i=0; i<nums.length; i++){
        if(nums[i]!=0){
            nums[cur++] = nums[i];
        }
    }
    for(;cur<nums.length; cur++){
        nums[cur] = 0;
    }
}

盛水最多的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
image.png

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。


解放1:双指针
在这里插入图片描述

在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1-1−1 变短:

  • 若向内 移动短板 ,水槽的短板 min(h[i],h[j])min(h[i], h[j])min(h[i],h[j]) 可能变大,因此下个水槽的面积 可能增大 。
  • 若向内 移动长板 ,水槽的短板 min(h[i],h[j])min(h[i], h[j])min(h[i],h[j]) 不变或变小,因此下个水槽的面积 一定变小 。

因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。

public int maxArea(int[] height) {
    int l = 0;
    int r = height.length-1;
    int area = 0;
    while(l<r){
        if(height[l]<height[r]){
            int cur = height[l]*(r-l);
            area = Math.max(area, cur);
            l++;
        }else{
            int cur = height[r]*(r-l);
            area = Math.max(area, cur);
            r--;
        }
    }
    return area;
}
func maxArea(height []int) int {
    l,r := 0,len(height)-1
    res := 0
    for l<r {
        if height[l] < height[r]{
            res = int(math.Max(float64(res),float64(height[l]*(r-l))))
            l++;
        }else{
            res = int(math.Max(float64(res),float64(height[r]*(r-l))))
            r--;
        }
    }
    return res
}

三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。


解法1:排序+双指针
先排序保证数据有序,这样就不会保存重复的数组了
接下来,外层循环确定一个 i 的值,内层循环使用左右两端向中间移动的双指针

//每个指针移动时跳过重复元素版,力扣不友好,时间还不如不跳过的快
public List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> res = new ArrayList<>();
    Arrays.sort(nums);
    int i=0; 
    while(i<nums.length-2){
        int sum = -nums[i];
        int j=i+1; 
        int k=nums.length-1;
        while(j<k){
            int cur = nums[j]+nums[k];
            if(cur > sum){
                while( j<k && nums[k]==nums[k-1])
                    k--;
                k--;
            }
            else if(cur < sum){
                while( j<k && nums[j]==nums[j+1])
                    j++;
                j++;
            }
            else{
                List<Integer> tmp = new ArrayList<>();
                tmp.add(nums[i]);
                tmp.add(nums[j]);
                tmp.add(nums[k]);
                res.add(tmp);
                while( j<k && nums[k]==nums[k-1])
                    k--;
                k--;
                while( j<k && nums[j]==nums[j+1])
                    j++;
                j++;
            }
        }
        while(i<nums.length-2 && nums[i+1]==nums[i])
            i++;
        i++;
    }
    return res;
}


//不跳过版
public List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> res = new ArrayList<>();
    Arrays.sort(nums);
    int i=0; 
    while(i<nums.length-2){
        int sum = -nums[i];
        int j=i+1; 
        int k=nums.length-1;
        while(j<k){
            int cur = nums[j]+nums[k];
            if(cur > sum)
                k--;
            else if(cur < sum)
                j++;
            else{
                List<Integer> tmp = new ArrayList<>();
                tmp.add(nums[i]);
                tmp.add(nums[j]);
                tmp.add(nums[k]);
                res.add(tmp);
                while(j<k&&nums[k]==nums[k-1])
                    k--;
                k--;
            }
        }
        while(i<nums.length-2 && nums[i+1]==nums[i])
            i++;
        i++;
    }
    return res;
}
func threeSum(nums []int) [][]int {
    res := make([][]int,0)
    sort.Ints(nums)
    for i,v:=range nums{
        if i==len(nums)-2 {break}
        if i>0&&nums[i]==nums[i-1] {continue}
        target := -v;
        l,r := i+1,len(nums)-1
        for l<r {
            sum := nums[l]+nums[r]
            if sum>target{
                for l<r&&nums[r]==nums[r-1]{r--}
                r--;
            }else if sum<target{
                for l<r&&nums[l]==nums[l+1]{l++}
                l++
            }else{
                res = append(res,[]int{v,nums[l],nums[r]})
                for l<r&&nums[l]==nums[l+1]{l++}
                l++
            }
        }
    }
    return res
}

接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。


解法1:最大前缀+最大后缀
对于每一个柱子能接的水,取决于:

  1. 当前柱子高度h0
  2. 当前柱子左侧最高的柱子h1,当前柱子右侧最高的柱子h2,取二者最小的值
  3. 当前柱子能接的水为:min(h1,h2)-h0
public int trap(int[] height) {
    int len = height.length;
    int pre[] = new int[len];
    int suf[] = new int[len];
    
    pre[0] = height[0];
    for(int i=1; i<len; i++){
        pre[i] = Math.max(pre[i-1],height[i]);
    }

    suf[len-1] = height[len-1];
    for(int i=len-2; i>=0; i--){
        suf[i] = Math.max(suf[i+1],height[i]);
    }

    int sum = 0;
    for(int i=0; i<len; i++){
        int low = Math.min(pre[i],suf[i]);
        sum += (low-height[i]);
    }

    return sum;
}
func trap(height []int) int {
    if len(height)<3 {
        return 0
    }
    leng := len(height)
    leftMax := make([]int,leng)
    rightMax := make([]int,leng)
    leftMax[0] = height[0]
    for i:=1; i<len(height); i++ {
        if(leftMax[i-1]>height[i]){
            leftMax[i] = leftMax[i-1]
        }else{
            leftMax[i] = height[i]
        }
    }
    rightMax[len(height)-1] = height[len(height)-1]
    for i:=len(height)-2; i>=0; i-- {
        if rightMax[i+1]>height[i] {
            rightMax[i] = rightMax[i+1]
        }else{
            rightMax[i] = height[i]
        }
    }
    res := 0
    for i:=0; i<len(height); i++ {
        var curHeight int
        if(leftMax[i]>rightMax[i]){
            curHeight = rightMax[i]
        }else{
            curHeight = leftMax[i]
        }
        res+=(curHeight-height[i])
    }
    return res
}

解法2:双指针,解法1的节省空间的方法
解法1为了维持每个位置的左右边界最大值,使用数组来表示,可以使用双指针来代替数组。
每次双指针移动之后比较最大值,小的一方先移动。

public int trap(int[] height) {
    int len = height.length;
    
    int res = 0;
    int left = 0;
    int right = len-1;
    int leftMax = 0;
    int rightMax = 0;

    while(left<=right){
        leftMax = Math.max(leftMax,height[left]);
        rightMax = Math.max(rightMax,height[right]);
        if(leftMax<=rightMax){
            res+=(leftMax-height[left++]);
        }else{
            res+=(rightMax-height[right--]);
        }
    }

    return res;
}

解法3:单调栈
栈内元素依然是单调递减。
image.png
当遇到相等的时候也要出栈,但是在计算面积的时候,由于左右边界中有一条边界和当前计算的柱子高度相等,所以高度差是0,计算出来也没影响。

public int trap(int[] height) {
    int len = height.length;
    Deque<Integer> stack = new ArrayDeque<>();

    int res = 0;

    for(int i=0; i<len; i++){
        while(!stack.isEmpty() && height[stack.peek()]<=height[i]){
            int curIndex = stack.pop();
            if(stack.isEmpty()) break;
            int preIndex = stack.peek();
            res+=((i-1-preIndex)*(Math.min(height[preIndex],height[i])-height[curIndex]));
        }
        stack.push(i);
    }

    return res;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

达梦数据库中的线程和进程

达梦数据库中的线程和进程 在达梦数据库中&#xff0c;线程和进程的概念与操作系统中的定义类似&#xff0c;但有一些特定的实现细节和用途。以下是达梦数据库中线程和进程的一些关键点&#xff1a; 进程&#xff08;Process&#xff09;&#xff1a; 在达梦数据库中&#x…

三分钟看懂马尔可夫链(Markov Chain)是什么

马尔可夫链&#xff08;Markov Chain&#xff09;是一种数学模型&#xff0c;用于描述系统在不同状态之间的转移过程。简单来说&#xff0c;马尔可夫链描述了一个系统在各个状态之间转移的概率&#xff0c;这种转移是随机的&#xff0c;但遵循特定的概率规则。它有两个重要特性…

SD卡讲解

SD 卡 (Secure Digital Memory Card) 在我们生活中已经非常普遍了&#xff0c;控制器对 SD 卡进行读写通信 操作一般有两种通信接口可选&#xff0c;一种是 SPI 接口&#xff0c;另外一种就是 SDIO 接口。SDIO 全称是安全数 字输入/输出接口&#xff0c;多媒体卡 (MMC)、SD 卡、…

财务RPA的ROI——如何计算财务RPA的回报率

近几年各企业纷纷利用RPA加速推进数字化转型进程&#xff0c;从企业效益角度来看&#xff0c;RPA能够帮助企业节省人力和运营成本&#xff0c;实现提质增效&#xff0c;但是每个企业运营管理的实际情况多有不同&#xff0c;在实施RPA前&#xff0c;还是要仔细评估投资和效益的问…

【鸿蒙学习笔记】元服务

官方文档&#xff1a;元服务规格 目录标题 什么是元服务特征第一个元服务-案例介绍创建项目源码启动模拟器启动entry创建卡片出发元服务 什么是元服务 特征 免安装分包预加载老化和更新机制 第一个元服务-案例介绍 创建项目 源码 Entry Component struct WidgetCard {buil…

33 IRF配置思路

IRF配置思路网络括谱图 主 Ten-GigabitEthernet 1/0/49 Ten-GigabitEthernet 1/0/50 Ten-GigabitEthernet 1/0/51 备 Ten-GigabitEthernet 2/0/49 Ten-GigabitEthernet 2/0/50 Ten-GigabitEthernet 2/0/51 思路 主 1 利用console线进入设备的命令行页面去更改…

SpringBoot入门(解决JDK8不存在问题)

1、什么是SpringBoot SpringBoot是一个用于创建独立的、基于Spring的Java应用程序框架。它通过约定优于配置的方式来简化Spring应用程序的开发过程&#xff0c;使开发者能够更快速地搭建和部署应用程序。Spring Boot 提供了自动化配置&#xff0c;减少了手动配置的工作量&#…

大数据专业创新人才培养体系的探索与实践

一、引言 随着大数据技术的迅猛发展&#xff0c;其在各行各业中的应用日益广泛&#xff0c;对大数据专业人才的需求也日益增长。我国高度重视大数据产业的发展&#xff0c;将大数据作为国家战略资源&#xff0c;推动大数据与各行业的深度融合。教育部也积极响应国家战略&#…

202-502SF 同轴连接器

型号简介 202-502SF是Southwest Microwave的连接器。这款连接器外壳采用不锈钢&#xff0c;接触件采用 BeCu 并进行金镀处理&#xff0c;绝缘体采用聚四氟乙烯&#xff0c;防尘环采用 UltiFume 1000&#xff0c;电缆适配器采用黄铜并进行金镀处理&#xff0c;电缆螺母也采用不锈…

跨境电商API的全球视野:打破地域限制,连接全球消费者与商家

在全球化日益加深的今天&#xff0c;跨境电商已成为推动全球经济一体化的重要力量。它不仅为消费者提供了前所未有的购物体验&#xff0c;让世界各地的商品触手可及&#xff0c;更为商家开辟了全新的市场蓝海&#xff0c;实现了业务的全球化拓展。在这一进程中&#xff0c;跨境…

基于vue的地图特效(飞线和标注)

这段代码的主要功能是在页面加载完成后&#xff0c;初始化一个 echarts 地图图表&#xff0c;并配置了相关的地理数据、散点数据、线条数据以及样式效果&#xff0c;最后在指定的 div 元素中进行展示。 需要再vue中的框架实现&#xff0c;不能单独直接运行。 标注 type: effe…

使用simulink进行esp32开发,进行串口收发数据需要注意的地方,为什么收发不成功

1&#xff0c;主要是因为simulink里的配置文件配置的波特率和串口接受软件配置的波特不一致导致的 2&#xff0c;主要有以下三个界面 a.配置文件 b.模型 模型直接选择使用的是那组串口就行了&#xff0c;一般情况下我们收发使用同一组就可以&#xff0c;这样收发模块填写的端…

浪潮服务器内存物理插槽位置

浪潮服务器内存物理插槽位置 如下图所示

光伏电站逆变器选型方法

前言&#xff1a;光伏逆变器是光伏发电系统两大主要部件之一&#xff0c;光伏逆变器的核心任务是跟踪光伏阵列的最大输出功率&#xff0c;并将其能量以最小的变换损耗、最佳的电能质量馈入电网。由于逆变器是串联在光伏方阵和电网之间&#xff0c;逆变器的选择将成为光伏电站能…

Socks5代理为何比HTTP代理快?

在网络世界中&#xff0c;代理服务器扮演着重要的角色&#xff0c;它们能够帮助我们访问被限制的网站、提高网络安全性以及优化网络性能。其中&#xff0c;Socks5代理和HTTP代理是两种常见的代理类型。然而&#xff0c;很多用户发现&#xff0c;相较于HTTP代理&#xff0c;Sock…

探索 Electron:窗口菜单以及生命周期和对话框讲解

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…

小程序问题

1.获取节点 wx.createSelectorQuery() wx.createSelectorQuery().in(this) //组件中加in(this)&#xff0c;不然获取不到 2.使用实例 wx.createSelectorQuery().in(this).select(#share).fields({node: true,size: true}).exec(async (res) > {const canvas res[0].node;…

【栈和队列OJ题】

栈和队列OJ题 文章目录 栈和队列OJ题1. 用队列实现栈2. 用栈实现队列3. 括号匹配问题4. 循环队列 1. 用队列实现栈 OJ链接&#xff1a;225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 好的&#xff0c;我们一起来看一下题目&#xff0c;题目是这样说的 思路&…

【斯坦福因果推断课程全集】2_无混淆和倾向分1

目录 Beyond a single randomized controlled trial Aggregating difference-in-means estimators Continuous X and the propensity score 随机试验的一个最简单的扩展是无约束下的干预效果估计。从定性上讲&#xff0c;当我们想估计一种并非随机的治疗效果&#xff0c;但一…

PyTorch | 加速模型训练的妙招

引言 提升机器学习模型的训练速度是每位机器学习工程师的共同追求。训练速度的提升意味着实验周期的缩短&#xff0c;进而加速产品的迭代过程。同时&#xff0c;这也表示在进行单一模型训练时&#xff0c;所需的资源将会减少。简而言之&#xff0c;我们追求的是效率。 熟悉 PyT…