删除排序数组中的重复项
题目:给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
- 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
- 返回 k 。
示例 :
输入:nums = [0,0,1,1,1,2,2,3,3,4] 输出:5, nums = [0,1,2,3,4]
算法思路:
首先该题的输入是一个为整数的数组。删除重复出现的元素可以用双指针的思路,右指针每一次向右移动一步,然后来判断该数和左指针的值是不是一样,如果一样右指针就向右再移动然后再判断;如果不一样,那么左指针就先向右移一步,然后把右指针的值赋值给左指针。循环的条件是直到右指针的长度小于数组的长度,然后输出左指针的长度。在最后如果想要输出[0,1,2,3,4],就需要使用切片的操作 list[start:end:step]。
python代码:
class Solution:
def removeDuplicates(self, nums):
right = 0
left = 0
while(right<len(nums)):
if(nums[right] == nums[left]):
right +=1
else:
left +=1
nums[left] = nums[right]
return left+1, nums[:left+1]
nums = [0,0,1,1,1,2,2,3,3,4]
solution = Solution()
removeDuplicates = solution.removeDuplicates(nums)
print(removeDuplicates)
买卖股票的最佳时机 II
题目:给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。返回 你能获得的 最大 利润 。
示例 :
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
算法思路:
之前没有了解过动态规划或者贪心算法,所以看到这个题就不会解。然后看了代码随想录里的详解,视频里用了贪心算法,所以这里我也用贪心算法。
贪心算法是先找到局部最优解,然后来找全局最优解。这个题中很巧妙的点是可以把所有的利润分解为每天的利润,然后最优的利润就是所有正的利润想加。所以这个题中局部最优点就是正的利润,全局最优就是所有正利润想加。
这个题的输入就是一组数组,需要输出的是最后的最大利润。很巧妙的是 result += max((nums[i] - nums[i-1]),0) 这一行,用当天的利润和0来取最大的值,这里真的很巧妙!!!
python代码:
#自己写的,注意 python里不支持 ++ 操作符
class Solution:
def Price(self, nums):
result = 0
i = 1
while(i<len(nums)):
result += max((nums[i] - nums[i-1]),0)
i +=1
return result
nums = [7,1,5,10,3,6,4]
solution = Solution()
price = solution.Price(nums)
print(price)
#代码随想录里的
class Solution:
def Price(self, nums):
result = 0
for i in range(1,len(nums)):
result += max((nums[i] - nums[i-1]),0)
return result
nums = [7,1,5,10,3,6,4]
solution = Solution()
price = solution.Price(nums)
print(price)
第二种写法更加简洁明了,使用了Python内置的range函数,省去了变量的定义和自增操作,代码更加简洁。
旋转数组
题目:给定一个整数数组 nums
,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
算法思路:
是否可以用双指针,一首一尾,但是数组只能靠覆盖来增删查,所以要一个一个的覆盖吗?这一步如何用代码来写呢?(用一个临时数组去储存)
但是更简单的是,直接用切片的方法来实现。从 len(nums) - k 这个点去切。值得注意的是,如果K大于len(nums),那么 nums[:] = nums[n - k : ] + nums[ : n-k] 将只会得到原来的数组,所以,需要加上这行 k = k % n代码,当k < n时,k % n==k; 当k > n, 就会得到正确的值,因为变换的话是n个变换为一个周期这样来变。
python代码:
class Solution:
def rotate(self, nums, k):
n = len(nums)
k = k % n
nums[:] = nums[n - k:] + nums[:n - k]
return nums[:]
nums = [1,2,3]
k = 5
solution = Solution()
rotate = solution.rotate(nums,k)
print(rotate)
存在重复元素
题目:给你一个整数数组 nums
。如果任一值在数组中出现 至少两次 ,返回 true
;如果数组中每个元素互不相同,返回 false
。
示例 :
输入:nums = [1,2,3,1] 输出:true
算法思路:
首先是暴力遍历法,但是运行时间超过了。然后看了其他解法,使用了set()集合。set()集合的特点是无序和不重复。根据不重复这个特点,就可以来解决这个题。它的思路是判断len(set(nums)) 和len(nums)是否相等,如果相等就说明没有重复的,不相等就说明有重复。
python代码:
#暴力法,超时了
class Solution:
def containsDuplicate(self,nums):
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if nums[i] ==nums[j]:
return True
return False
nums = [1,2,3,1]
solution = Solution()
containsDuplicate = solution.containsDuplicate(nums)
print(containsDuplicate)
#使用set()集合
class Solution:
def containsDuplicate(self, nums):
if len(set(nums)) != len(nums):
return True
return False
nums = [1,2,3,4]
solution = Solution()
containsDuplicate = solution.containsDuplicate(nums)
print(containsDuplicate)
注意:使用 set(nums) 时,实际上 Python 会自动将列表 nums 中的元素提取出来并创建一个包含这些元素的集合。在这个过程中,它并不是直接把列表作为一个整体添加到集合中,而是对列表中的每个元素进行处理,将不重复的元素放入新创建的集合中。但是使用 set.add()时,就不能直接 set.add(nums),需要一个一个的放。
只出现一次的数字
题目:给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
注:你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 :
输入:nums = [4,1,2,1,2] 输出:4
算法思路:
当我不知道不能直接 set.add(nums)时,我不知道可以使用set集合。但是了解后,就可以根据set集合的“冲突”来解决这个问题,首先要创建一个集合(去存这个只出现一次的数),然后遍历这个数组,如果数组里的元素在这个集合里,就从集合里面删除,如果不在就添加。但是这样,不用创集合,创数组是不是也可以呢?-(也可以)(但是以下的代码的时间复杂度是n*n.)
python代码:
#set集合,添加元素用的是 add
class Solution:
def singleNumber(self,nums):
result_set = set()
for num in nums:
if num in result_set:
result_set.remove(num)
else:
result_set.add(num)
return list(result_set)[0]
nums = [1,2,2,3,3]
solution = Solution()
singleNumber = solution.singleNumber(nums)
print(singleNumber)
#列表添加元素是用 append()
class Solution:
def singleNumber(self,nums):
result = []
for num in nums:
if num in result:
result.remove(num)
else:
result.append(num)
return result[0]
nums = [1,2,2,3,3]
solution = Solution()
singleNumber = solution.singleNumber(nums)
print(singleNumber)
#抓住 只有一个数出现一次,其它都是两次这个题目。绝了啊
class Solution:
def singleNumber(self, nums):
return sum(set(nums)) * 2 - sum(nums)
nums = [1,2,2,3,3]
solution = Solution()
singleNumber = solution.singleNumber(nums)
print(singleNumber)
还有一个很妙的方法是使用位运算:
a^a=0;自己和自己异或等于0
a^0=a;任何数字和0异或还等于他自己
a^b^c=a^c^b;异或运算具有交换律
而题目中有说 只有一个数出现了一次,其他数字都出现了2次。所以不需要创集合或者数组来存储,只需要一个整数,然后一个一个的和数组里的数进行异或运算,最后就会得到那只出现一次的数,代码是:
class Solution(object):
def singleNumber(self, nums):
a=0
for num in nums:
a^=num
return a
nums = [1,2,2,3,3]
solution = Solution()
singleNumber = solution.singleNumber(nums)
print(singleNumber)
两个数组的交集 II
题目:给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
算法思路:
先对两个数组进行排序(sorted()默认是从小到大),然后使用两个指针,分别指向两个数组开始的位置。如果两个指针指向的值相同,说明这个值是他们的交集,就把这个值加入到集合list中,然后两个指针在分别往后移一步。如果两个指针指向的值不同,那么指向的值相对小的往后移一步,相对大的先不动,然后再比较
另外一种方法是使用map来解决:
map()函数通常有两个参数(函数对象,可迭代对象)
python代码:
class Solution(object):
def intersect(self,nums1,nums2):
n1 = sorted(nums1)
n2 = sorted(nums2)
l1 = len(nums1)
l2 = len(nums2)
right = 0
left = 0
result = []
while((right < l1) and (left < l2)):
if(n1[right] == n2[left]):
result.append(n1[right])
right +=1
left +=1
elif(n1[right] > n2[left]):
left +=1
elif(n1[right] < n2[left]):
right +=1
return result
加一
题目:
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入:digits = [1,2,3] 输出:[1,2,4] 解释:输入数组表示数字 123。
算法思路:
题目应该就是想问999+1咋办?把数组转化成一个数,然后该数加一,然后再把这个数变成数组?这样也可以,但是看了答案,使用了以下代码, for i in range(len(digits)-1, -1, -1)这行代码是从后向前的遍历,其中在for循环里面的return很关键,可以仔细品品。for循环就是从后向前的把9变成0,如果都是9则不会在for循环里面的return,如果没有9则直接加1后跳出循环返回结束了。
python代码:
class Solution(object):
def plusOne(self, digits):
for i in range(len(digits)-1, -1, -1): #倒序
if digits[i] == 9:
digits[i] = 0
else:
digits[i] += 1
return digits
#全是9的情况,然后需要加1
digits.insert(0,1)
return digits
digits = [9,9]
solution = Solution()
plusOne = solution.plusOne(digits)
print(plusOne)
移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12] 输出: [1,3,12,0,0]
算法思路:
自己的思路是,遇到不是0的就加在另外的一个数组里,然后遇到是0的就添加在最前面(倒叙添加没有成功),然后通过反转列表输出,在自己本地跑是成功的,但是没有提交通过。看了参考答案,妙啊,没有添加新的数组,在原来的数组中操作,只对不为0的进行遍历,然后使用nums[i],nums[j]=nums[j],nums[i] 这行代码进行交换,完全想不出来,妙啊!!!多看几遍吧!!!
python代码:
#用了新的列表,然后在本地跑的答案是正确的,但是没有通过
class Solution(object):
def moveZeroes(self, nums):
num1 =[]
left = len(num1)
for i in range(len(nums)-1,-1,-1):
if nums[i] != 0:
num1.append(nums[i])
else:
num1.insert(0,0)
return num1[::-1]
nums = [0,1,0,3,12,0]
solution = Solution()
moveZeroes = solution.moveZeroes(nums)
print(moveZeroes)
#例题答案
class Solution(object):
def moveZeroes(self, nums):
j=0
for i in range(len(nums)):
if nums[i] !=0 :
nums[i],nums[j]=nums[j],nums[i]
j+=1
return nums
nums = [0,1,0,3,12,0]
solution = Solution()
moveZeroes = solution.moveZeroes(nums)
print(moveZeroes)
两数之和
题目:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
算法思路:
双指针?也可以,但是时间复杂度很高,给的参考答案就很妙!!!使用了字典!!!多看几遍这种方法吧,大大的降低了时间复杂。
python代码
class Solution(object):
def twoSum(self,nums,target):
for right in range(len(nums)):
for left in range(right+1,len(nums)):
if nums[right] + nums[left] == target:
return right,left
nums = [3,2,4]
target = 6
solution = Solution()
twoSum = solution.twoSum(nums,target)
print(twoSum)
class Solution(object):
def twoSum(self, nums, target):
h = {}
for i, num in enumerate(nums):
n = target - num
if n not in h:
h[num] = i
else:
return [h[n], i]
nums = [3,2,4]
target = 6
solution = Solution()
twoSum = solution.twoSum(nums,target)
print(twoSum)
有效的数独
题目:请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)