1.283. 移动零
给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums =[0,1,0,3,12]
输出:[1,3,12,0,0]
示例 2:
输入: nums =[0]
输出:[0]
提示:
1 <= nums.length <= 10^4
-2^31 <= nums[i] <= 2^31 - 1
思路:
一个指针指向非0元素,一个指针指向0元素,然后交换数据,接着继续遍历
直到两个指针指向位置的元素都为0,终止!!
代码:
void moveZeroes(int* nums, int numsSize) {
int i,j;
i=0,j=1;
while(nums[i]!=0 && nums[j]!=0){
while(nums[j]==0 && j<numsSize)j++;//指向非0数
while(nums[i]!=0 && i<numsSize)i++;//指向0
//交换i,j对应的数
int temp;
temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
}
为啥不对呀不对呀,奇怪了,插个眼,难道是交换的方式有问题?
代码的问题,我果断python;
class Solution(object):
def moveZeroes(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
if not nums:
return 0
# 两个指针i和j
j = 0
for i in xrange(len(nums)):
# 当前元素!=0,就把其交换到左边,等于0的交换到右边
if nums[i]:
nums[j],nums[i] = nums[i],nums[j]
j += 1
2.11. 盛最多水的容器
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 2:
输入:height = [1,1] 输出:1
思路:
设两指针 i , j ,指向的水槽板高度分别为 h[i] , h[j] ,此状态下水槽面积为 S(i,j)S 。由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :
在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1-1−1 变短:
若向内 移动短板 ,水槽的短板 min(h[i],h[j])可能变大,因此下个水槽的面积 可能增大 。
若向内 移动长板 ,水槽的短板 min(h[i],h[j])不变或变小,因此下个水槽的面积 一定变小 。
因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。
代码:
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
i,j=0,len(height)-1
max_area=0
while i!=j :
area=min(height[i],height[j])*(j-i)
max_area= max(area,max_area)#当更大的面积出现时,替换当前最大
if i<j :
i+=1
else:
j-=1
return max_area
未能全部AC;检查一下:
喝醉了,判断移位的地方咋搞得,脑子瓦特了!
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
i,j=0,len(height)-1
max_area=0
while i!=j :
area=min(height[i],height[j])*(j-i)
max_area= max(area,max_area)#当更大的面积出现时,替换当前最大
if height[i]<height[j] :
i+=1
else:
j-=1
return max_area
全部AC!
3.15. 三数之和
先不多说,来个随想录分录!代码随想录 (programmercarl.com)
详细讲解!
给你一个整数数组 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
-10^5 <= nums[i] <= 10^5
思路:
先对数组排序,一个for循环用于确定a,然后使用双指针left,right分别指向b,c;
判断:如果a+b+c>0,则将right--;如果a+b+c<0,则将left++。
满足条件的三元组,将nums[i],nums[left],nums[right]放入一个大数组中,形成一个二维数组。
但是要注意这些内容里面的去重细节,因为不可以出现重复情况。
代码:
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
#先排序
nums.sort()
result=[]
for i in range(0,len(nums)):
if i>0 and nums[i]==nums[i-1]:#a的去重
continue;
left=i+1
right=len(nums)-1
print(left,right)
while left<right :
if nums[i]+nums[left]+nums[right] > 0 :
right-=1
elif nums[i]+nums[left]+nums[right]<0:
left+=1
else:
result.append([nums[i],nums[left],nums[right]])
#找到答案要加入时,对b,c去重
while left<right and nums[right]==nums[right-1]:right-=1
while left<right and nums[left]==nums[left+1]:left+=1
#找到答案以后,同时收缩
left+=1
right-=1
return result
注意点
1.中间[0,0,0]的去重,需要着重在本行代码里加上判断:
if i>0 and nums[i]==nums[i-1]:#a的去重
continue;
这里虽然要对a去重,但要排除全0的情况。
2.对bc的去重逻辑应该放在找到一个三元组之后,对b 和 c去重。详见代码
4.42. 接雨水
标签困难!!!!(这个留个位置,还要再学一下具体的双指针思路!)
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 2:
输入:height = [4,2,0,3,2,5] 输出:9提示:
n == height.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
思路:
代码:
一位力扣大神的:
class Solution {
public int trap(int[] height) {
int sum = 0;
//最两端的列不用考虑,因为一定不会有水。所以下标从 1 到 length - 2
for (int i = 1; i < height.length - 1; i++) {
int max_left = 0;
//找出左边最高
for (int j = i - 1; j >= 0; j--) {
if (height[j] > max_left) {
max_left = height[j];
}
}
int max_right = 0;
//找出右边最高
for (int j = i + 1; j < height.length; j++) {
if (height[j] > max_right) {
max_right = height[j];
}
}
//找出两端较小的
int min = Math.min(max_left, max_right);
//只有较小的一段大于当前列的高度才会有水,其他情况不会有水
if (min > height[i]) {
sum = sum + (min - height[i]);
}
}
return sum;
}
}
搬运一个对双指针的解释: 可算看懂了,原来双指针同时开两个柱子接水。 对于每一个柱子接的水,那么它能接的水=min(左右两边最高柱子)-当前柱子高度,这个公式没有问题。同样的,两根柱子要一起求接水,同样要知道它们左右两边最大值的较小值。
问题就在这,假设两柱子分别为 i,j。那么就有 iLeftMax,iRightMax,jLeftMx,jRightMax 这个变量。由于 j>i ,故 jLeftMax>=iLeftMax,iRigthMax>=jRightMax.
那么,如果 iLeftMax>jRightMax,则必有 jLeftMax >= jRightMax,所有我们能接 j 点的水。
如果 jRightMax>iLeftMax,则必有 iRightMax >= iLeftMax,所以我们能接 i 点的水。
而上面我们实际上只用到了 iLeftMax,jRightMax 两个变量,故我们维护这两个即可。