今天刷的还是关于双指针这一类型的题目,通过做题也可以发现有些题目可以使用相同的思想。
移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(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,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素
思路:其实这道题想了很久,Leecode上面已经给出了该例题。
如果我们不使用额外的数组,只是在原数组上进行操作呢?
此时,我们就可以采用快慢指针的思想:初始化一个快指针 fast 和一个慢指针 slow,fast 每次移动一步,而 slow 只当 fast 指向的值不等于 val 时才移动一步。
该题就是这种思路,定义快慢指针slow和fast,遍历数组元素,如果nums[fast]!=val,将当前nums[slow]=nums[right],slow++;最后放回数组元素长度,当时脑子比较混乱,逻辑一时理不太清。
class Solution {
public int removeElement(int[] nums, int val) {
int len=nums.length;
int slow=0;
for(int fast=0;fast<len;fast++)
{
if(nums[fast]!=val){
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}
}
第二题:移动0
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
思路:该题也可以使用快慢指针思路,将0都移除掉,然后再让slow后面的索引补0就可以了。
class Solution {
public void moveZeroes(int[] nums) {
int slow=0;
int len=nums.length;
for(int fast=0;fast<len;fast++){
if(nums[fast]!=0){
nums[slow]=nums[fast];
slow++;
}
}
for(;slow<len;slow++){
nums[slow]=0;
}
}
}
第三题:
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例 1:输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
示例 2:输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:输入:numbers = [-1,0], target = -1
输出:[1,2]
思路:注意数组升序排列,所以双指针分别指向数组开头和结尾,定义一个数组存放答案,
class Solution {
public int[] twoSum(int[] numbers, int target) {
int []result=new int[2];
if(numbers.length<2)
{
return null;
}
int left=0;
int right=numbers.length-1;
while(left<=right){
if(numbers[left]+numbers[right]==target)
{
result[0]=left+1;
result[1]=right+1;
break;
}
else if(numbers[left]+numbers[right]<target)
{
left++;//如果大于target,left右移
}
else{
right--;//如果大于target,right左移
}
}
return result;
}
}
在做题时,经常会用到一些函数。
math类中的一些方法
Math.sqrt()
: 计算平方根Math.cbrt()
: 计算立方根Math.pow(a, b)
: 计算a的b次方Math.max( , )
: 计算最大值Math.min( , )
: 计算最小值Math.abs()
: 取绝对值Math.ceil()
: 天花板的意思,就是逢余进一Math.floor()
: 地板的意思,就是逢余舍一Math.rint()
: 四舍五入,返回double值。注意.5的时候会取偶数Math.round()
: 四舍五入,float时返回int值,double时返回long值
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
输入:[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来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
public class Solution { public int maxArea(int[] height) { int l = 0, r = height.length - 1; int ans = 0; while (l < r) { int area = Math.min(height[l], height[r]) * (r - l); ans = Math.max(ans, area); if (height[l] <= height[r]) { ++l; } else { --r; } } return ans; } }