全国第四轮学科评估结果查询
最近出了高考成绩,有些学弟学妹找我咨询志愿填报的问题。
无论是“地域优先论”,还是“学校优先论”,或者是“专业优先论”,我都持平等的看法。
读大学,说到底还是对一个人基本素质的培养,其他都是虚的。不过,为了满足学弟学妹们的需要,我也整理了一些资料,提供给大家。
为GitHub的私有项目添加合作者
当你在GitHub中当仓库设置为private时,对外是不可见的,对方无法从GitHub主页查找你,也无法通过你分享的网址查找你。
想要让其他人加入到这个私人项目中,可以添加合作者。
未命名
@TOC
第一题
代码
python版本
1 | class MyLinkedList: |
第二题
代码
python版本
1 | class Solution: |
第三题
代码
python版本
1 | class Solution: |
第四题
83. 删除排序链表中的重复元素 - 力扣(LeetCode)
代码
python版本
1 | class Solution: |
第五题
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
代码
python版本
1 | class Solution: |
未命名
@TOC
这里介绍双指针在数组中的第二类题型:两端夹击。
第五题
题目描述:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例1:
1 | 输入:nums = [-4,-1,0,3,10] |
思路
因为是排序每个数字的平方,根据二次函数图像y=x^2开口向上可得,最大值在两端,最小值在中间。所以,最左和最右进行比较,两端夹击,看谁的平方值更大。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
第六题
题目描述:
给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
示例1:
1 | 输入:numbers = [2,7,11,15], target = 9 |
思路
可以先考虑边界情况。升序数组中任意两个元素求和,最小为nums[0]+nums[1],最大为nums[n-2]+nums[n-1]。target的范围一定在这两者之间,否则找不到答案。所以,我们可以两端夹击,一直手抓nums[0],另一只手抓nums[n-1]。如果是最小的情况,那么让nums[n-1]向nums[1]靠拢;如果是最大的情况,那么让nums[1]向nums[n-2]靠拢。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
第七题
题目描述:
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a^2 + b^2 = c 。
示例1:
1 | 输入:c = 5 |
思路
上一题是两个数的和是否为target,这道题是两个数的平方和是否为target。一样的思路,考虑最大最小值。若两个数的平方和为target,则最小为0,最大为target的平方根。同样的,两端夹击。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
下一篇博客LeetCode算法题解——双指针3中,我将分享LeetCode中关于字符串的双指针问题。
参考:
未命名
@TOC
接上文LeetCode算法题解——二分查找2,本篇分享LeetCode中几道比较难想到使用二分查找解法的题目。
第八题
题目描述:
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。
示例1:
1 | 输入: nums = [1,1,2,3,3,4,4,8,8] |
思路
我们先思考一下,没有单一元素的nums,如[1,1,3,3,4,4,8,8]具有什么样的规律。不难发现,对于每一个偶数下标i=2k的nums[i],它的值都等于后一位nums[i+1]的值。但是在插入2之后,这种规律只会在2之前存在。在2之后,所有奇数下标i=2k+1的nums[i],都等于nums[i+1]。
所以,我们只需要找到中点m附近的偶数下标,通过判断nums[i]=nums[i+1]这种规律是否存在,就可以判断中点m是在插入的单一元素之前还是之后。如果这种规律存在,那么说明中点m在单一元素之前,需要收缩左边界;如果这种规律不存在,那么说明中点m在单一元素之后,需要收缩右边界。
收缩左边界时,因为已经知道nums[m] = nums[m+1],所以l=m+2。收缩右边界时,nums[m] != nums[m+1],则必定有nums[m+1]= nums[m+2],所以r=m。
最后,搜索区间不断缩小,不断将成对的元素排除在区间之外。当区间长度为1时,区间内的元素就是单一元素。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
之前的二分查找是查找一个target,这道题的二分查找是查找一种关系。某个点之前,这种关系满足,在某个点之后,这种关系不满足。我们需要通过判断关系的满足与否,缩小搜索区间,找出这个点。
第九题
题目描述:
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
示例1:
1 | 输入:nums = [3,4,5,1,2] |
思路
根据单调性,对于升序nums,其任意一点m,其右侧任意一点都大于等于左侧任意一点,即nums[m+] >= nums[m-]。如果发生旋转,则在旋转点k,其右侧任意一点都小于等于左侧任意一点,即nums[k+] <= nums[k-]。通过上一题,我们可以知道,二分查找可以通过缩小搜索区间,找出这种使关系发生变化的点。
旋转点左侧为第一分枝,右侧为第二分枝。我们的目标就是,通过缩小收缩区间,找到第二分枝的左端点,即为旋转点。如果中点m在第二分枝上,根据单调性,有r > m && nums[r] >= nums[m],那么收缩r=m,使得r保持在第二分枝上。如果r=m-1的话,无法保证还在第二分枝,因为我们只验证过r和m的单调性,没有验证r和m-1的单调性。如果中点m在第一分枝上,则恰好r在旋转点(即第二分枝左端点)右侧,m在旋转点左侧,有nums[r] < nums[m],那么抛弃中点m及其左边的点,l=m+1。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
上面两道题使用二分查找解题的关键都在于,能够将要找的target与某种关系联系起来。在target的左侧,满足某种关系;在target的右侧,不满足这种关系。
第十题
代码
python版本
1 | class Solution: |
第十一题
题目描述:
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例1:
1 | 输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5 |
思路
在上面两道题中我已经谈到了,可以使用二分查找将target与某种关系联系起来,在target的左侧满足某种关系,而在target的右侧不满足这种关系。在这道题中,这种关系是结构上的。对于任意一个元素,其所在行自左向右递增,所在列自上而下递增。特别的,对于每一行最右的元素m,其左的所在行元素都比它小,其下的所在列元素都比它大。因此,如果给定一个target和m进行比较,target小于m则应该向其左的所在行元素继续比较;target大于m则应该向其下的所在列元素继续比较。如果m的位置超出矩阵的合法范围,则说明找不到target。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
这一题和前面两题一样,都需要寻找一种关系作为突破口。在某个点之前,这种关系存在;在某个点之后,这种关系不存在。
第十二题
题目描述:
给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
你必须找到一个内存复杂度优于 O(n2) 的解决方案。
示例1:
1 | 输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8 |
思路
我们先分析这道题为什么可以用二分查找来解决。正如前面三题所示,能够用二分查找解决的问题都存在一种关系,在target之前满足这种关系,在target之后不满足这种关系。让我们来看示例1,在数组[1,5,9,10,11,12,13,13,15]中,如果一个元素是target,那么数组中比它小的元素有8个;如果一个元素小于target,那么数组中比它小的元素小于8个;如果一个元素大于target,那么数组中比它小的元素大于8个。这种关系的存在,使得我们可以用二分查找来解决这道题。在这里,给出一个二分查找的思路作为参考,二分,超级简单。
关于这个思路,很多人会纠结的一点是,如何验证最后求得的l在数组中?其实就是在问,如果一个元素是target,那么数组中比它小的元素有8个;反过来,如果数组中比一个数小的元素有8个,那么这个元素到底是不是target?不难发现,“一个元素是target,那么数组中比它小的元素有8个”是个充分不必要条件。不妨把数组[1,5,9,10,11,12,13,13,15]最后的15改成30来讨论这个问题。对于数组[1,5,9,10,11,12,13,13,30],我们还是寻找第8小的元素,正确答案应该是13。但是,在13和30中间,其实还有很多个数满足“数组中比一个数小的元素有8个”这个条件。准确来说,14,15,…,29都满足这个条件。我称这些数为“影子target”。很多人就会纠结,按照二分,超级简单的思路,那么如何排除掉这些“影子target”?这里我们就得先想明白,为什么会存在“影子target”。简单来说,“影子target”就是target和target后一位之间的间隙。如果我们把最后一位改成20,那么正确答案还是13,“影子target”是14,15,…,19。如果我们把数组改成[1,5,9,10,11,12,13,16,20],那么正确答案是16,“影子target”是17,18,19。那么,我们会发现,16是满足“数组中比一个数小的元素有8个”这个条件的最小的数。
让我们从头思考一下这个问题。为什么我们可以用二分查找来解决这道问题?因为在数组中,如果一个元素是target,那么数组中比它小的元素个数cnt等于8;如果一个元素小于target,那么数组中比它小的元素个数cnt小于8;如果一个元素大于target,那么数组中比它小的元素cnt大于8。所以,我们可以用二分查找解决这道题。cnt小于8,则l=m+1;cnt大于8,则r=m-1。但是,cnt等于8时,我们就找到target了吗?上面已经分析过了,如果cnt等于8,那么这个元素不一定是target,还有可能是“影子target”。因为在target和target后一位之间,还有间隙。那么我们如何找到正确的target呢?我们已经发现,真实target就是满足cnt等于8的最小值,所以我们就是在找满足cnt等于8这个条件的左边界。既然是找左边界,在上一篇博客中我已经讨论过了,其实就是在找到满足cnt等于8这个条件的元素时,不要直接返回结果,而是继续收缩右边界。
代码
1 | class Solution { |
python版本
1 | class Solution: |
总结
这道题不难想到用二分查找来解决。一般人或许可以想到用官方题解差不多的二分法。但是,上面介绍的二分法,需要对为什么可以用二分法,用二分法是查找target还是左/右边界有深刻的理解。
未命名
@TOC
接上文LeetCode算法题解——二分查找1,本篇总结LeetCode中部分题目的二分查找解法。
第四题(寻找左边界)
题目描述:
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例1:
1 | 输入:n = 5, bad = 4 |
思路
如果将n个版本的true和false放到一个数组里,应该是[false, false, …, true, true],前面都是false,后面都是true。这道题可以看作是找到最后一个false,也可以看作是找到第一个true。在这里,我将它当作找到第一个true来做,也就是寻找true的左边界。
代码
java版本
1 | public class Solution extends VersionControl { |
python版本
1 | class Solution: |
总结
在寻找左边界的时候,和之前中点值找到target一样,找到就收缩右边界。拓展一下,在寻找左/右边界,找到了target,但还没有到达其边界,应该向你要搜索的边界靠近,进一步压缩搜索空间。
第五题(寻找右边界)
题目描述:
给你一个字符数组 letters,该数组按非递减顺序排序,以及一个字符 target。letters 里至少有两个不同的字符。
返回 letters 中大于 target 的最小的字符。如果不存在这样的字符,则返回 letters 的第一个字符。
示例1:
1 | 输入: letters = ["c", "f", "j"],target = "a" |
思路
按照题意,寻找第一个比target大的字母。在前面寻找右边界时我们已经提到,当循环停止时右边界r以右的元素都大于target,则右边界r以左的元素都小于等于target,右边界r即最后一个target。所以,第一个比target大的字母就是r+1处的字母。但是当target比数组中所有数字都要大的时候,r+1会越界,这里需要做特别处理。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
这道题,需要将大于 target 的最小的字符理解成第一个比target大的字符,并且知道可以通过寻找target的右边界来求解。
第六题(找一个数)
题目描述:
给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
不能使用任何内置的库函数,如 sqrt 。
示例1:
1 | 输入:num = 16 |
思路
首先思考一种暴力算法。以num=16为例,我们先从1开始穷举。1*1=1,1<16,不满足。2*2=4,4<16,不满足。3*3=9,9<16,不满足。4*4=16,16==16,满足!5*5=25,25>16,不满足。显然,比4小的数和比4大的数,都不满足,我们可以通过二分法筛选掉比4小的数和比4大的数。
值得注意的是,如果直接比较x*x和num,可能x*x会超过int的范围。可以转化为比较x和num/x。如果是这样的话,考虑到整数除法结果仍然为整数,当x=num/x时,num可能是x*x,x*x+1,…,x*x+(x-1)。此时只需要再次比较x*x和num,即可。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
这道题,我们可以先思考一个穷举的办法,然后考虑可以用二分法进行优化。防止溢出是一个需要注意的点。这道题里,m是中点,sqrt是target。和以前不同,这道题的target是会变的。
第七题(找右边界)
题目描述:
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
示例1:
1 | 输入:x = 8 |
思路
这题和上一题不同。在上一题中,完全平方数,如16,一定能找到整数4*4=16。但是在这题里,将平方根的小数部分舍去了,那么就不能通过x*x=num来进行判断。同样的,我们先思考一种暴力算法。以num=8为例,我们先从1开始穷举。1*1=1,1<8;2*2=4,4<8;3*3=9,9>8。显然,前面的平方数都比8小,后面的平方数都比8大,我们需要找到最后一个比8小的平方数。问题转化为了找比8小的平方数的右边界。
和上一题一样,如果直接比较x*x和num,可能x*x会超过int的范围,可以转化为比较x和num/x。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
同样的,这道题我们先思考一个穷举的办法,然后考虑可以用二分法进行优化。防止溢出依旧是一个需要注意的点。这道题里,m是中点,sqrt是target,会发生改变。
下一篇博客LeetCode算法题解——二分查找3中,我将分享LeetCode中几道比较难想到使用二分查找解法的题目。
参考:
未命名
@TOC
常用的二分查找包括:寻找一个数、插入target、寻找左右边界。
第一题(寻找一个数)
题目描述:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例1:
1 | 输入: nums = [-1,0,3,5,9,12], target = 9 |
思路
二分法,如果找到target,直接返回;如果target比中点值小,说明在左区间,则缩小右端点;如果target比中点值大,说明在右区间,则缩小左端点。
代码
c++版本
1 | int binarySearch(vector<int> nums, int target) |
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
本题有两点需要注意。
第一点,搜索区间是“左闭右闭”。之所以选择“左闭右闭”的搜索区间,是为了在缩小左、右端点的时候可以统一操作。此外,因为搜索区间是“左闭右闭”的,所以循环条件是左端点小于等于右端点。
第二点,取中点的计算要防溢出。
第二题(插入target)
题目描述:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例1:
1 | 输入: nums = [1,3,5,6], target = 2 |
思路
如果找得到,则参考上题代码。如果找不到,循环停止时,左边界l以左(不包含l)的元素都小于target,右边界r以右(不包含r)的元素都大于target。所以,target应该插入左边界l的位置,这样其左侧元素皆小于target,其右侧元素皆大于target。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
循环停止时,左边界l以左(不包含l)的元素都小于target,右边界r以右(不包含r)的元素都大于target。所以,target应该插入左边界l的位置,这样其左侧元素皆小于target,其右侧元素皆大于target。
第三题(寻找左右边界)
题目描述:
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例1:
1 | 输入:nums = [5,7,7,8,8,10], target = 8 |
思路
先考虑左边界。和前面两题不同,这题找到target不能直接返回,要继续寻找,直到找到第一个target。当循环停止时,左边界l以左的元素都小于target,则左边界l以右的元素都大于等于target,左边界l即第一个target。所以,当找到target的时候,仍然缩小右边界,向左边界靠拢。
同理,搜索右边界时,当找到target不能直接返回,要继续寻找,直到找到最后一个target。当循环停止时,右边界r以右的元素都大于target,则右边界r以左的元素都小于等于target,右边界r即最后一个target。所以,当找到target的时候,仍然缩小左边界,向右边界靠拢。
得到了左右边界,也只是说明如果有target,那第一个和最后一个target就是左右边界。但是,存在没有target的可能,所以还需要对左右边界进行判断。值得注意的是,可能target比所有的元素都大,此时左边界l等于数组长度,需要先判断是否越界,再判断左边界是否为target。同样的,可能target比所有的元素都小,此时右边界l等于-1,需要先判断是否越界,再判断右边界是否为target。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
总结
本题有三点需要注意。
第一点,理解为什么左右边界就是第一个和最后一个target。当循环停止时,左边界l以左的元素都小于target,则左边界l以右的元素都大于等于target,左边界l即第一个target。当循环停止时,右边界r以右的元素都大于target,则右边界r以左的元素都小于等于target,右边界r即最后一个target。
第二点,当找到target的时候左右边界如何移动。寻找左边界时,需要右边界向左边界靠拢,所以找到target时仍然缩小右边界。寻找右边界时,需要左边界向右边界靠拢,所以找到target时仍然缩小左边界。
第三点,防止左右边界越界。左右边界是target“应该”出现的第一个和最后一个位置,到底是不是还需要经过验证。验证之前,记得考虑左右边界是否越界。
下一篇博客LeetCode算法题解——二分查找2,我将总结LeetCode中部分题目的二分查找解法。
参考:
未命名
@TOC
这里介绍双指针在数组中的第一类题型:一个数组当两个用。
第一题
题目描述:
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例1:
1 | 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 |
思路
一个简单的想法,借助新建数组nums3来完成nums1和nums2的合并。如果nums1[0]小于nums2[0],则将nums1[0]放入nums3[0],继续比较nums1[1]和nums2[0]。同样的,如果nums2[0]小于nums1[0],则将nums2[0]放入nums3[0],继续比较nums2[1]和nums1[0]。直到将nums1或nums2遍历完,剩下未遍历的部分可以直接放入nums3。
但是,题目要返回的是nums1而不是nums3。那么我们有两个办法来对上述的方法进行优化。第一个办法,最后遍历nums3,用nums3的元素替换nums1的元素。第二个办法,直接在nums1上进行上述的操作。如果要在nums1上进行上述的操作,那么就需要从大到小比较,先把最大的元素放到nums1最右侧,以免覆盖了未参与比较的nums1元素。
直接把nums1数组当nums3数组来用,就是双指针的精髓所在。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
第二题
题目描述:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例1:
1 | 输入:nums = [3,2,2,3], val = 3 |
思路
如果不要求原地修改,那很简单。只需要新建数组nums1,从左到右扫描nums的元素,如果nums的元素不等于val,则将其放入nums1;如果等于val,则跳过。
但是,现在要求原地修改,也就是要一个数组当作两个用。和上一题一样,有两种办法。第一种办法,可以先把元素放在数组nums1,然后再用nums1的元素去覆盖nums的元素。第二种办法,可以直接把nums数组当nums1数组。但是,这样会不会导致nums原有的元素被覆盖呢?实际上是不会的,我们思考一下,如果用idx1扫描nums,非val元素通过idx2存放到nums1,那么idx1总是大于等于idx2的。也就是说,idx2使用的区域,idx1早就扫描过了。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
第三题
题目描述:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例1:
1 | 输入: nums = [0,1,0,3,12] |
思路
这题和上一题很相似,都是遇到val(0)就跳过。但是不同的是,这道题不仅要跳过val,还要把val放到后面去。有两种办法,第一种是和第二题一样,遇到val的时候就跳过val,然后再把后面都填充为val;第二种是让val和非val进行交换。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
第四题
题目描述:
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例1:
1 | 输入:nums = [1,1,2] |
思路
如果不是原地修改,那我们还是考虑新建数组nums1。nums[0]肯定是不重复的,可以放到nums1[0]。因为nums是有序的,从nums[1]开始,如果和前面的元素相同,那么说明是重复的,可以跳过;如果和前面的元素不同,那么说明不重复,放入nums1数组。
如果要原地修改,还是同样的情况,有两种办法。第一种办法就是用nums1去覆盖nums。第二种办法,要一个数组当作两个用。我们总是要思考,会不会覆盖未扫描的元素?看得出,fast总是比slow跑得快,所以不会覆盖。
代码
java版本
1 | class Solution { |
python版本
1 | class Solution: |
下一篇博客LeetCode算法题解——双指针2中,我将分享LeetCode中另一种类型的双指针问题。
参考:
未命名
- 使用Adobe Acrobat(首推)
有招啦!轻松实现Word文档批量转换为PDF - 使用Mac的自动操作
Mac下实现批量Word或PPT转PDF - 使用LibreOffice
如何在 macOS 上一键批量把 PPT 和 Word 文件转成 PDF