力扣刷题笔记

十大排序算法

菜鸟教程链接

数组

704.二分法查找有序数组目标值

https://leetcode.cn/problems/binary-search/

思路:分别定义两个变量储存目标数组的最左和最右元素的索引left 和right,middle = (left + right)//2 比较 middle索引处与target值进行大小比较,来更新left和right,使得目标数组范围不断缩小,直到找到目标值,如果left>right时还没有找到,则返回-1

from typing import List


class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1
        while left <= right:
            middle = (left + right) // 2
            if nums[middle] > target:
                right = middle - 1
            elif nums[middle] < target:
                left = middle + 1
            else:
                return middle
        return -1


a = Solution()
b = a.search([-1, 0, 3, 5, 9, 12], 9)
print(b)

2022.7.24

34. 在排序数组中查找元素的第一个和最后一个位置

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

'''
采用二分法的思路, 分两次分别用来查找左边界和右边界,计算出来的左边界是不包含target的左边界,右边界同理
寻找target在数组里的左右边界,有如下三种情况:
情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
'''
from typing import List


class Solution:
    @classmethod
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def get_right_border(nums: List[int], target: int) -> int:
            left = 0
            right = len(nums) - 1
            right_border = -2
            while left <= right:
                middle = (left + right) // 2
                if nums[middle] <= target: # 等于target时,更新left
                    left = middle + 1
                    right_border = left
                else:
                    right = middle - 1
            return right_border

        def get_left_border(nums: List[int], target: int) -> int:
            left = 0
            right = len(nums) - 1
            left_border = -2
            while left <= right:
                middle = (left + right) // 2
                if nums[middle] < target:
                    left = middle + 1
                else:# 等于target时,更新right
                    right = middle - 1
                    left_border = right
            return left_border

        left_border = get_left_border(nums, target)
        right_border = get_right_border(nums, target)

        # 情况一
        if left_border == -2 or right_border == -2:
            return [-1, -1]
        # 情况三
        if right_border - left_border > 1:
            return [left_border + 1, right_border -1]
        # 情况二
        return [-1, -1]

27.移除元素(双指针)

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 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],也会被视作正确答案。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

'''
双指针思路:快指针用来获取新数组元素 而慢指针用来指向新数组元素的位置
'''
from typing import List


class Solution:
    @classmethod
    def removeElement(self, nums: List[int], val: int) -> int:
        fast = 0
        slow = 0
        for fast in range(len(nums)):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
        return slow


a = Solution;
b = a.removeElement([1, 2, 3], 2)
print(b)

977. 有序数组的平方(双指针)

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/squares-of-a-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

'''
因为是有序,所以数组两侧的元素平方是最大的,比较两者的最大值则为新数组的最大值,新数组从后往前填入即可
'''
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l = len(nums)
        left = 0
        n = right = l - 1
        res = [-1] * l
        while n >= 0:
            left_2 = nums[left] * nums[left]
            right_2 = nums[right] * nums[right]
            if left_2 >= right_2:
                res[n] = left_2
                left += 1
            else:
                res[n] = right_2
                right -= 1
            n -= 1
        return res

2022.7.25

209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:

输入:target = 4, nums = [1,4,4]
输出:1
示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-size-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

from typing import List


class Solution:
    '''
    暴力解法(力扣会超时):采用两侧循环依次找出所有数组的首位和末尾,然后判断是否满足条件
    '''

    # def minSubArrayLen(self, target: int, nums: List[int]) -> int:
    #     n = len(nums)
    #     res = n + 1
    #     for i in range(0, n):
    #         for j in range(i, n):
    #             adds = 0
    #             adds += nums[j]
    #             if adds >= target:
    #                 tmp = j + 1 - i
    #                 if tmp < res:
    #                     res = tmp
    #             break
    #     if res == n + 1:
    #         return 0
    #     return res

    '''
    滑动窗口法:用j作为目标数组的右边界,左边界i=0,j通过for循环进行遍历并求和,当求和结果大于等于target时,i才往后进行移动以求出满足条件的最短目标数组
    '''
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n = len(nums)
        i = 0
        res = float("inf")
        sums = 0
        for j in range(0, n):
            sums += nums[j]
            while sums >= target:
                res = min(res, j + 1 - i)
                sums = sums - nums[i]
                i += 1
        return 0 if res == float("inf") else res


a = Solution()
b = a.minSubArrayLen(4, [1, 4, 4])
print(b)

2022.7.28

59.螺旋矩阵II

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:
在这里插入图片描述
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:

输入:n = 1
输出:[[1]]

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/spiral-matrix-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

from typing import List


'''
思路:每次循环都进行一圈数字的写入,每个圈按照四个for循环分别写入四个边的值,而每个边都按照规则进行左闭右开的写入
'''
class Solution:
    @classmethod
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)] # 表达式理解: https://blog.csdn.net/jinyeran/article/details/122451822
        startx = 0
        starty = 0
        loop = n // 2  # 迭代次数
        mid = n // 2   # n 为奇数时,矩阵的中心点
        count = 1 # 计数

        for offset in range(1, loop + 1):  # 每循环一层偏移量加1,偏移量从1开始
            for i in range(starty, n - offset):  # 从左至右  左闭右开
                nums[startx][i] = count
                count += 1
            for i in range(startx, n - offset):  # 从上至下
                nums[i][n - offset] = count
                count += 1
            for i in range(n - offset, starty, -1): # 从右至左
                nums[n - offset][i] = count
                count += 1
            for i in range(n - offset, startx, -1): # 从下至上
                nums[i][starty] = count
                count += 1
            startx += 1  # 更新起始点
            starty += 1

        if n % 2 != 0:  # n为奇数时,填充中心点
            nums[mid][mid] = count
        return nums

哈希表

242.有效的字母异位词(哈希表)

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:

输入: s = “rat”, t = “car”
输出: false

提示:

1 <= s.length, t.length <= 5 * 104
s 和 t 仅包含小写字母

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-anagram
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

'''
思路:使用一个长度为26的数组用来储存每个字母的出现次数,首先遍历s数组,利用
record[ord(s[i]) - ord("a")] += 1 对 s 字符串中每个字母的出现字数进行统计
然后再遍历 t 字符串,对应位置的数量减一,最后判断record数组里面的元素是否都为0,如果都为 0,
代表s t 这两个字符串中字母的出现次数一致,返回true,否则返回false
'''
class Solution:
    @classmethod
    def isAnagram(self, s: str, t: str) -> bool:
        record = [0] * 26
        for i in range(len(s)):
            record[ord(s[i]) - ord("a")] += 1
        for i in range(len(t)):
            record[ord(t[i]) - ord("a")] -= 1
        for i in range(26):
            if record[i] != 0:
                return False

        return True


a = Solution()
b = Solution.isAnagram("abc", "bac")
print(b)

2022.8.1

202.快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2:

输入:n = 2
输出:false

提示:

1 <= n <= 231 - 1

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/happy-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

'''
注意题目字眼:无限循环,也就是说如果sum一直不等于 1 的话会无限循环下去,sum会重复出现,因此采用哈希表来记录所有的sum,判断sum是否重复出现,如果重复出现,返回false,否则当判断sum = 1 时,为快乐数,返回true
'''
class Solution:
    def isHappy(self, n: int) -> bool:
        def get_happy_sum(num):
            sum_ = 0

            while num:
                sum_ += (num % 10) ** 2
                num = num // 10
            return sum_

        record = set()

        while True:
            n = get_happy_sum(n)
            if n == 1:   # 是快乐数
                return True

            if n in record:  # 如果中间结果重复出现,说明陷入死循环了,该数不是快乐数
                return False
            else:
                record.add(n)

2022.8.4

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

from typing import List

'''
思路:(可暴力通过),下面这个思路是采用的哈希法,用一个字典来储存已经遍历过的元素value和index,每次遍历时,判断target - val是否存在在字典中(因为是用key储存的,查询会很快),如果存在则返回结果,不存在则村岑
'''
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        records = dict()

        # 用枚举更方便,就不需要通过索引再去取当前位置的值
        for idx, val in enumerate(nums):
            if target - val not in records:
                records[val] = idx
            else:
                return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引

454. 四数相加 II

给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:

  1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
  2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
    示例 2:

输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/4sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

from typing import List

'''
思路:分两次进行查找,首先遍历nums1 nums2用字典储存所有和的结果以及组合这个和的种数
然后遍历nums3 nums4所有的和,判断与之组合等于0的num1 num2 的和在字典中是否存在
存在的话计数器加上该和的种类数,否则查找下一个
'''
class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int],
                     nums4: List[int]) -> int:
        hashmap = dict()
        for n1 in nums1:
            for n2 in nums2:
                if n1 + n2 in hashmap:
                    hashmap[n1 + n2] += 1
                else:
                    hashmap[n1 + n2] = 1

        count = 0
        for n3 in nums3:
            for n4 in nums4:
                key = 0 - (n3 + n4)
                if key in hashmap:
                    count += hashmap[key]

        return count

2022.8.8

15.三数之和(双指针)

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:

输入:nums = []
输出:[]
示例 3:

输入:nums = [0]
输出:[]

提示:

0 <= nums.length <= 3000
-105 <= nums[i] <= 105

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

from typing import List
'''
思路:关键在于去重,哈希表不合适,采用双指针的思路
首先对数组进行排序,首先通过 i 索引遍历数据,作为第一个数 a 为了对 a 进行去重,如果当前的 a 与前一位 i-1 位置的数字相同,则不处理,进行下一位的循环
然后创建两个数组 left = i + 1    right = len(nums) - 1 分别指向 i 指针后面数组的第一位和最后一位,对 i left right 三个位置的数进行求和
如果 total < 0  left += 1   如果 total > 0   right -= 1  等于 0 时 则找到符合条件的三个数字 然后对 left right后续的数字进行去重,
如果后续数字相同,则进行跳过
'''

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        ans = list()
        n = len(nums)
        nums.sort()
        for i in range(n):
            left = i + 1
            right = n - 1
            if nums[i] > 0:
                break
            if i >= 1 and nums[i] == nums[i - 1]:  # a 去重
                continue
            while left < right:
                total = nums[i] + nums[left] + nums[right]
                if total > 0:
                    right -= 1
                elif total < 0:
                    left += 1
                else:
                    ans.append([nums[i], nums[left], nums[right]])
                    while left != right and nums[left] == nums[left + 1]: left += 1  # left 去重
                    while left != right and nums[right] == nums[right -1]: right -= 1 # right 去重
                    left += 1
                    right -= 1
        return ans

a = Solution()
lis = [-1,0,1,2,-1,-4]
b = a.threeSum(lis)
print(b)

18.四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

from typing import List

'''
思路:跟三数之和一样的思路,在外面再套上一层循环来遍历新增的 k 索引
因为此时要求求的是 target 不再是 0 因此再进行剪枝操作时不能简单的通过 nums[k] > target 的条件就决定减去,因为target可能是负数,
索引只有当 nums[k] > 0 时,确保其之后的数组都为正数时,才可以进行剪枝
'''


class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        res = []
        for k in range(n):
            if nums[k] > target and nums[k] > 0:  # 剪枝
                break
            if k > 0 and nums[k] == nums[k - 1]: continue  # 去重
            for i in range(k + 1, n):
                if nums[k] + nums[i] > target and nums[k] + nums[i] > 0:  # 剪枝
                    break
                if i > k + 1 and nums[i] == nums[i - 1]: continue  # 去重
                left = i + 1
                right = n - 1

                while left < right:
                    if nums[k] + nums[i] + nums[left] + nums[right] > target:
                        right -= 1
                    elif nums[k] + nums[i] + nums[left] + nums[right] < target:
                        left += 1
                    else:
                        res.append([nums[k], nums[i], nums[left], nums[right]])
                        while left < right and nums[left] == nums[left + 1]: left += 1
                        while left < right and nums[right] == nums[right - 1]: right -= 1
                        left += 1
                        right -= 1
        return res

贪心算法

11111111

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值