LeetCode刷题之数组篇

No.18 (Medium)

题目

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

思路

做了3Sum我们可以知道,这类题目的通解就是排序后先固定前几个然后对最后的剩余两个数做2Sum。为了得到普适性的解法,我们直接做NSum。我们不妨用递归算法来解决这道题,我们需要建立一个列表储存前面几个数然后每次递归把它与2Sum的结果合并加入到总结果中。

代码

class Solution:
    def __init__(self, title): 
        self.title = title
        
    def NSum(self, nums, target, N):
        nums.sort()
        result_list = []
        self.findNSum(nums, target, N, [], result_list)
        return result_list
    
    def findNSum(self, nums, target, N, result, results):
        if N < 2 or len(nums) < N:
            print("wrong N")
            return
        if nums[-1]*N < target or nums[0]*N > target:
            return
        if N == 2:
            i, j = 0, len(nums)-1
            while i < j:
                if nums[i] + nums[j] < target:
                    while i < j and nums[i] == nums[i + 1]:
                        i += 1
                    i += 1
                elif nums[i] + nums[j] > target:
                    while i < j and nums[j] == nums[j - 1]:
                        j -= 1
                    j-=1
                else:
                    results.append(result + [nums[i], nums[j]])
                    while i < j and nums[i] == nums[i + 1]:
                        i += 1
                    while i < j and nums[j] == nums[j - 1]:
                        j -= 1
                    i += 1
                    j -= 1
        else:
            for i in range(len(nums) - N + 1):
                if i > 0 and nums[i] == nums[i - 1]:
                    continue
                self.findNSum(nums[i+1:], target - nums[i], N-1, result + [nums[i]], results)
                # here the result + [nums[i]] is a very smart point, it prevent updating result
        return 

知识回顾

Python的函数对number, string, tuple按值传递,会创建副本。而对list, dict是按引用传递

No.33(Medium)

题目

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm’s runtime complexity must be in the order of O(log n).

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

思路

这道题其实就是对二分法排序的变式,只不过这里不能简单的二分,因为从一个地方倒转了一下。但我们可以发现一个规律,数组的第一个元素就是我们的倒转点,故通过中点与查找值与第一个元素进行比对,我们就可以知道他们是不是属于有序的一边。

代码

class Solution:
    def __init__(self, title): 
        self.title = title
        
    def BinarySearch(self, nums, target):
        i, j = 0, len(nums) - 1
        while i < j:
            mid = int((i + j)/2)
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                i = mid + 1
            else:
                j = mid - 1
        if i == j and nums[i] == target:
            return i
        return -1
    
    def search(self, nums, target):
        i, j = 0, len(nums) - 1
        while i < j:
            mid = int((i + j)/2)
            cri = nums[i]
            if nums[mid] == target:
                return mid
            elif cri == target:
                return i
            elif nums[mid] > cri:
                if target > cri:
                    if nums[mid] < target:
                        i = mid + 1
                    else:
                        j = mid - 1
                else:
                    i = mid + 1
            elif nums[mid] < cri:
                if target < cri:
                    if nums[mid] < target:
                        i = mid + 1
                    else:
                        j = mid - 1
                else:
                    j = mid - 1
            else:
                i += 1
        if i == j and nums[i] == target:
            return i
        return -1

No.34(Medium)

题目

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm’s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

思路

我们把这个问题转化成两个问题,寻找最小的target插入位置和最小的target + 1插入位置。这里插入位置指的是把原来的元素挤到后面去并保持原来的顺序。那么显然这两个位置就是我们要的边界值。而我们只需要研究寻找最小target插入位置的算法(Log(n)代价)。

代码

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def search(n):
            lo, hi = 0, len(nums)
            while lo < hi:
                mid = int((lo + hi) / 2)
                if nums[mid] >= n:
                # here needs some attention: as we want the first position to insert value, 
                # we include the "=" situation in the right part
                    hi = mid
                else:
                # we use "mid + 1" because a element which is smaller than target can never be a insert position
                # furthermore, it solve the problem when the interval between lo and hi is just 1
                    lo = mid + 1
            return lo
        lo = search(target)
        return [lo, search(target+1)-1] if target in nums[lo:lo+1] else [-1, -1]
        # here we use [lo:lo +1] instead of nums[lo] because lo might larger than the bound

No.39(Medium)

题目

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:

Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
Example 2:

Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

思路

这种找到所有结果的题目一般都是用动态规划算法做的。想法是不断地用target减去列表中的元素,如果减到0那么就是一条正确的道路,如果是负数就舍弃。难点在于怎么确保不会重复,其实只用每次降阶的时候只取当前元素之后的元素即可。这里我还做了一下排序操作,这样可以大大减少后面的递归个数。

知识回顾

在Python函数中,如果参数是list的话,那么就是按引用传递,会改变list的值。所以我们如果想用动态规划的算法储存path,每次不要把path.append()放在参数中,第一它返回的是None,第二它会改变列表本身。直接path + [i] 即可

代码

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        candidates.sort()
        self.dfs(candidates, target, 0, [], res)
        return res
    
    def dfs(self, nums, target, index, path, res):
        if target == 0:
            res.append(path)
            return
        else:
            for i in range(index, len(nums)):
                if target < nums[i]:
                    break
                self.dfs(nums, target - nums[i], i, path + [nums[i]], res)
                # here use "path + [nums[i]]" instead of "path.append(nums[i])" because it will unstoppingly adding element in path

No.40(Medium)

题目

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
Example 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
[1,2,2],
[5]
]

思路

这里和前面一题的区别在于这里有重复项,而且每一个元素只能用一次。那么显然我们dfs函数的index部分要变成i+1。那么怎么解决重复项问题(如果和原来一样,得到的结果会有重复的),唯一的方法是加入nums[i] == nums[i - 1] continue这一操作。但这样有可能没有用到下一个重复的元素,所以加入一个i > index的条件

代码

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        candidates.sort()
        self.dfs(candidates, target, 0, [], res)
        return res
    
    def dfs(self, nums, target, index, path, res):
        if target == 0:
            res.append(path)
            return
        else:
            for i in range(index, len(nums)):
                if i > index and nums[i] == nums[i - 1]:
                    continue
                   # here is very delicate. as i has already larger than index, we can use i - 1
                if target < nums[i]:
                    break
                self.dfs(nums, target - nums[i], i + 1, path + [nums[i]], res)

知识回顾

这里dfs不用针对index溢出情况研究。因为range(a,b)a可以大于b的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值