专题【双指针】【学习题】刷题日记

题目列表

11. 盛最多水的容器
42. 接雨水
15. 三数之和
16. 最接近的三数之和
18. 四数之和
26. 删除有序数组中的重复项
27. 移除元素
75. 颜色分类
167. 两数之和 II - 输入有序数组


2024.04.06

11. 盛最多水的容器

题目

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

示例 1:
在这里插入图片描述

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

示例 2:

输入:height = [1,1]
输出:1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

思路

  1. 从图可知,接水量=Math.min(left, right) * (rightIndex - leftIndex)
  2. 可以用双指针
  3. 因为要找最大值,而且双指针相向而行(宽度在变小),只有最小高度变大才可能有最大值,所以移动高度相对较低的一端

答案

class Solution {public int maxArea(int[] height) {int length = height.length;if (length < 2) {return 0;}int left = 0;int right = length - 1;int leftH = height[left];int rightH = height[right];int result = 0;while (left < right) {int h = Math.min(leftH, rightH);result = Math.max(result, h * (right - left));if (leftH == h) {left++;// 此处快速收敛一下,因为leftH >= height[left],就不可能更大while (left < right && leftH >= height[left]) {left++;}leftH = height[left];} else {right--;// 同left处while (left < right && rightH >= height[right]) {right--;}rightH = height[right];}}return result;}
}

42. 接雨水

题目

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

示例 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 个单位的雨水(蓝色部分表示雨水)。

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

思路

和上一题的区别是,上一题认为每个位置的高度都是0,本题是有一个基础高度
所以不能简单的用high * length,要逐个计算高度
整体思路和上一题类似,区别是每个格子能盛水的量是,Math.min(左max,右max)

答案

class Solution {public int trap(int[] height) {int length = height.length;if (length < 2) {return 0;}int left = 0;int right = length - 1;int leftHMax = height[left];int rightHMax = height[right];int result = 0;// 因为计算高度在判断后进行。判断后会进行一次位移,left和right会重合,这里不需要left <= rightwhile (left < right) {int minMax = Math.min(leftHMax, rightHMax);if (minMax == leftHMax) {left++;if (height[left] < minMax) {result += minMax - height[left];} else {leftHMax = height[left];}} else {right--;if (height[right] < minMax) {result += minMax - height[right];} else {rightHMax = height[right];}}}return result;}
}

15. 三数之和

题目

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

注意: 答案中不可以包含重复的三元组。

示例 1:

输入: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] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

思路

  1. 循环每一个数,然后变为newTarget = target - nums[i]的两数之和
  2. 排序之后,循环每一个数,然后双指针。
  3. newTarget = target - nums[i]。left + right = newTarget。
  4. 因为排序,left向右则和变大,right向左则和变小
  5. 综上,用双指针

答案

class Solution {public List<List<Integer>> threeSum(int[] nums) {int length = nums.length;sorted(nums, 0, length - 1);List<List<Integer>> result = new ArrayList<>();for (int i = 0; i < length - 1; i++) {if (nums[i] > 0) {return result;}// 去除重复元素if (i > 0 && nums[i] == nums[i - 1]) {continue;}int target = -nums[i];int left = i + 1;int right = length - 1;while (left < right) {int sum = nums[left] + nums[right];if (sum == target) {result.add(Arrays.asList(nums[i], nums[left], nums[right]));// 去除重复元素,这里用left和left+1对比,而不是用left和left-1对比,是为了后续移动left统一操作while (left < right && nums[left] == nums[left+1]) {left++;}// 去除重复元素while (left < right && nums[right] == nums[right - 1]) {right--;}left++;right--;} else if (sum < target) {left++;} else {right--;}}}return result;}// 顺便练习下,有重复元素的快排(颜色分类用到了)public void sorted(int[] nums, int left, int right) {if (left >= right) {return;}// min指向小于element元素的下一个值(不包含)[left, mid)是小于element的// mid指向当前遍历元素[min, mid)是和element相等的值// max是指向第一个比element大的元素的左边的元素,(max, right] 比element大// [mid, max]是未遍历元素int min = left, mid = min + 1, max = right;int element = nums[min];while (mid <= max) {int current = nums[mid];if (element == current) {mid++;} else if (element < current) {swap(nums, mid, max--);} else {swap(nums, min++, mid++);}}//因为min和max都是开区间,所以,这里做一个位移sorted(nums, left, min - 1);sorted(nums, max + 1, right);}private void swap(int[] nums, int index1, int index2) {int temp = nums[index1];nums[index1] = nums[index2];nums[index2] = temp;}
}

2024.04.07

16. 最接近的三数之和

题目

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

提示:

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

思路

同上三数之和,可以作为练习题

答案

class Solution {public int threeSumClosest(int[] nums, int target) {int length = nums.length;int result = 0;sorted(nums, 0, length - 1);int min = Integer.MAX_VALUE;for (int i = 0; i < length; i++) {int nums1 = nums[i];int left = i + 1;int right = length - 1;while (left < right) {int sum = nums1 + nums[left] + nums[right];// 判断差值if (Math.abs(sum - target) < min) {min = Math.abs(sum - target);result = sum;}// 找到直接截断if (sum ==  target) {return sum;} else if (sum < target) {left++;} else {right--;}}}return result;}private void sorted(int[] nums, int left, int right) {if (left >= right) {return;}int element = nums[left];int min = left, mid = min + 1, max = right;while (mid <= max) {int current = nums[mid];if (current == element) {mid++;} else if (current < element) {swap(nums, min++, mid++);} else {swap(nums, mid, max--);}}sorted(nums, left, min - 1);sorted(nums, max + 1, right);}private void swap(int[] nums, int index1, int index2) {int temp = nums[index1];nums[index1] = nums[index2];nums[index2] = temp;}
}

18. 四数之和

题目

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • a、b、c 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

  • 1 <= nums.length <= 200
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109

思路

和三数之和类似
区别是

  1. 需要两次循环
  2. length条件不一样
  3. nums[i]的条件不一样,可能相加之后溢出

答案

class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {List<List<Integer>> result = new ArrayList<>();int length = nums.length;if (length < 4) {return result;}sorted(nums, 0, length - 1);for (int i = 0; i < length - 3; i++) {long first = nums[i];// 快速截断,已经超过目标值了if (first + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {break;}// 快速截断,不可能达成if (first + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {continue;}if (i > 0 && nums[i] == nums[i - 1]) {continue;}for (int j = i + 1; j < length - 2; j++) {// 同上if (first + nums[j] + nums[j + 1] + nums[j + 2] > target) {break;}// 同上if (first + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {continue;}if (j > i + 1 && nums[j] == nums[j - 1]) {continue;}int second = nums[j];int left = j + 1;int right = length - 1;while (left < right) {long sum = first + second + nums[left] + nums[right];if (sum == target) {result.add(Arrays.asList((int) first, second, nums[left], nums[right]));while (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}left++;right--;} else if (sum < target) {left++;} else {right--;}}}}return result;}private void sorted(int[] nums, int left, int right) {if (left >= right) {return;}int element = nums[left];int min = left, mid = min + 1, max = right;while (mid <= max) {int current = nums[mid];if (current == element) {mid++;} else if (current < element) {swap(nums, min++, mid++);} else {swap(nums, mid, max--);}}sorted(nums, left, min - 1);sorted(nums, max + 1, right);}private void swap(int[] nums, int index1, int index2) {int temp = nums[index1];nums[index1] = nums[index2];nums[index2] = temp;}
}

26. 删除有序数组中的重复项

题目

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = […]; // 输入数组
int[] expectedNums = […]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过。

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 非严格递增 排列

思路

  1. 一个size记录新的大小
  2. 如果下一个元素和当前元素相等,size就不动
  3. 否则size+1,并把当前位置的元素复制过来

答案

class Solution {public int removeDuplicates(int[] nums) {int size = 0;// 看提示,可以确认大小范围int last = -100000;for (int i = 0; i < nums.length; i++) {if (nums[i] == last) {continue;} else {nums[size++] = nums[i];last = nums[i];}}return size;}
}

27. 移除元素

题目

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,3,0,4]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

思路

和上一题相同。区别是,size变更的条件
上一题是last和当前不相等
这个一题是val和当前不相等

答案

class Solution {public int removeElement(int[] nums, int val) {int size = 0;for (int i = 0; i < nums.length; i++) {int current = nums[i];if (current == val) {continue;} else {nums[size++] = nums[i];}}return size;}
}

75. 颜色分类

题目

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 0、1 或 2

进阶:

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

思路

重复元素排序

元素

class Solution {public void sortColors(int[] nums) {sorted(nums, 0, nums.length - 1);}private void sorted(int[] nums, int left, int right) {if (left >= right) {return;}int element = nums[left];int min = left, mid = min + 1, max = right;while (mid <= max) {int current = nums[mid];if (element == current) {mid++;} else if (current < element) {swap(nums, min++, mid++);} else {swap(nums, mid, max--);}}sorted(nums, left, min - 1);sorted(nums, max + 1, right);}private void swap(int[] nums, int index1, int index2) {int temp = nums[index1];nums[index1] = nums[index2];nums[index2] = temp;}
}

167. 两数之和 II - 输入有序数组

题目

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

提示:

  • 2 <= numbers.length <= 3 * 104
  • -1000 <= numbers[i] <= 1000
  • numbers 按 非递减顺序 排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案

思路

三数之和的简单版本

答案

class Solution {public int[] twoSum(int[] numbers, int target) {int l = 0, r = numbers.length - 1;while (l < r) {int current = numbers[l] + numbers[r];if (current > target) {r--;} else if (current < target) {l++;} else {// 题目要求从1开始return new int[] { l + 1, r + 1 };}}return new int[2];}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信息论基础:生日问题

生日问题 我的小学同班同学小琦&#xff0c;和我是同一天生日。每次聚会&#xff0c;我俩同时在场时&#xff0c;我们都会向其他人提起这一点。我们觉得这是很幸运的。 这个概率大吗&#xff1f;要回答这样的问题&#xff0c;需要把几个问题区分清楚。 问题1&#xff1a;对于…

EXCEL地理数据处理工具(地图任务)

版本号 作者 修订内容 发布日期 1.0 小O 更新至0705版 2022-4-28 1.1 小O 更新至0772版 2024年4月3日 一、概述 小O地图EXCEL插件版提供基于EXCEL表格进行地理数据处理、地图可视化、地图绘图等功能&#xff0c;地理工具是用户使用频率很高的功能模块。地理工具能…

2024HW-->Wireshark攻击流量分析

在HW中&#xff0c;最离不开的&#xff0c;肯定是看监控了&#xff0c;那么就要去了解一些wireshark的基础用法以及攻击的流量&#xff01;&#xff01;&#xff01;&#xff01; 1.Wireshark的基本用法 比如人家面试官给你一段流量包&#xff0c;你要会用 1.分组详情 对于我…

构建未来数字化世界的统一用户中心产品架构

随着数字化时代的到来&#xff0c;用户数据管理变得愈发复杂&#xff0c;各类应用和服务的涌现使得用户信息分散存储&#xff0c;导致了数据孤岛和体验碎片化的问题。在这样的背景下&#xff0c;统一用户中心产品架构应运而生&#xff0c;为构建数字化世界提供了全新的解决方案…

Linux 常用指令及其理论知识

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;http://t.csdnimg.cn/Tvyou 欢迎各位指教&#xff01;&#xff01;&#xff01; 目录 一、理论知识 二、基础指令 1、ls指令&#xff08;列出该目录下的所有子目录和文件&#xff09; 语法&#xff1a; …

基于单片机电容介电常数测量显示系统设计

**单片机设计介绍&#xff0c;基于单片机电容介电常数测量显示系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机电容介电常数测量显示系统的设计&#xff0c;是一个集成了电子技术、单片机编程、电容测量以及显…

GD32F470_寻迹避障模块 TCRT5000红外反射传感器模块移植

2.6 红外循迹传感器 红外循迹传感器采用TCRT5000红外反射传感器&#xff0c;一种集发射与接收于一体的光电传感器&#xff0c;它由一个红外发光二极管和一个NPN红外光电三极管组成。检测反射距离1mm-25mm适用&#xff0c;传感器特设M3固定安装孔&#xff0c;调节方向与固定方便…

websokcet服务端实现

一/websokcet服务端实现 步骤一&#xff1a; springboot底层帮我们自动配置了websokcet&#xff0c;引入maven依赖 1 2 3 4 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</arti…

红黑树深度解析:LEFT-ROTATE操作的艺术与实践

红黑树深度解析&#xff1a;LEFT-ROTATE操作的艺术与实践 一、什么是LEFT-ROTATE&#xff1f;二、LEFT-ROTATE的步骤三、LEFT-ROTATE的效果四、例子五、伪代码示例六、伪代码示例七、结论 在二叉搜索树中&#xff0c;旋转操作是维护树平衡的重要技术之一&#xff0c;特别是在红…

STC89C51学习笔记(三)

STC89C51学习笔记&#xff08;三&#xff09; 综述&#xff1a;本文讲述了通过51单片机控制LED闪烁、流水灯、按键控制LED亮灭、按键控制LED实现二进制、按键控制LED左右移。 一、LED 1.LED闪烁 1&#xff09;LED电路原理 LED采用共阳极&#xff0c;当LED另一端为低电平时…

GA-SVM,基于GA遗传算法优化SVM支持向量机回归预测(多输入单输出)

基于遗传算法&#xff08;Genetic Algorithm, GA&#xff09;优化支持向量机&#xff08;Support Vector Machine, SVM&#xff09;用于回归预测是一个常见的任务。在这个任务中&#xff0c;我们使用GA来寻找SVM的最佳超参数配置&#xff0c;以最大化回归性能指标&#xff0c;例…

一文带你初识DDD领域驱动设计

DDD是什么&#xff1f; DDD&#xff08;Domain-driven design&#xff09;&#xff0c;是领域驱动设计的缩写。 然而&#xff0c;领域驱动设计&#xff0c;是什么&#xff1f;很多书籍&#xff0c;很多博客&#xff0c;都没有对领域驱动设计下一个标准的定义。 就连《实现领…