python:LeetCode刷题笔记

题号69: 二分:实现 int sqrt(int x) 函数

实现 int sqrt(int x) 函数
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1: 输入: 4 输出: 2
示例 2: 输入: 8 输出: 2
说明: 8 的平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。

该题可以利用牛顿迭代法进行求解:
链接:https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
ALT
python代码:

class Solution(object):
    def mySqrt(self, x):
        """
        :type x: int
        :rtype: int
        """
        if x <= 1:
            return x
        else:
            xk = x
            while x / xk < xk:
                xk = (xk + x / xk) // 2
            return int(xk)

题目160:链表:链表相交

题目描述:编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
ALT
第一种方法:先计算两个链表的长度差,然后分别向后遍历,找到第一个引用相同的节点
代码:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        currentA = headA
        currentB = headB
        skipA = 0
        skipB = 0
        while currentA:
            currentA = currentA.next
            skipA += 1
        while currentB:
            currentB = currentB.next
            skipB += 1
        
        if skipA >= skipB:
            gap = skipA - skipB
            while gap:
                headA = headA.next
                gap -= 1
            while headA and headB:
                if headA == headB:
                    return headA
                headA = headA.next
                headB = headB.next
            return 
        else:
            gap = skipB - skipA
            while gap:
                headB = headB.next
                gap -= 1
            while headA and headB:
                if headA == headB:
                    return headA
                headA = headA.next
                headB = headB.next
            return             

第二种方法:
法3: 同时对A和B进行遍历, 并且让到达末尾的指针指向另一个链表的头结点. 例如A: 6->7->4->5; B: 1->2->3->4->5 遍历时会相交于4 (67451234, 12345674).
代码:

    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        p1 = headA
        p2 = headB
        while p1 != p2:
            p1 = p1.next if p1 else headB
            p2 = p2.next if p2 else headA
        return p1

题号1 哈希表:两数之和

哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。
哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。

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

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
例:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路:先定义一个空字典,对数组进行遍历,判断每一个差是否在字典里
代码:

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        # n = len(nums)
        # for i in range(n):
        #     diff = target - nums[i]
        #     if diff in nums[i+1:]:
        #         return list([i, nums[i+1:].index(diff) + i + 1])
        n = len(nums)
        d = {}
        for i in range(n):
            diff = target - nums[i]
            if nums[i] in d:
                return [d[nums[i]], i]
            else:
                d[diff] = i   

题号242 :字符串:字母异位词

题目描述:
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。
示例:

输入: s = "anagram", t = "nagaram"
输出: true

思路:

  • 什么是异位词

两个单词如果包含相同的字母,次序不同,则称为字母易位词(anagram)

  • 异位词特点

字符数相同/顺序不同/出现字符相同

  • 思路

既然是找寻字符串的不同,那我们可以直接建立对应的 哈希表,来对两个 hash 表 进行操作
在比对的时候可以达到O(1)的复杂度

代码:

class Solution(object):
    def isAnagram(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        # ss = sorted(s)
        # tt = sorted(t)
        # if ss == tt:
        #     return True
        # else:
        #     return False
        dicts, dictt = {}, {}
        for ss in s:
            if ss in dicts:
                dicts[ss] += 1
            else:
                dicts[ss] = 1
        for tt in t:
            if tt in dictt:
                dictt[tt] += 1
            else:
                dictt[tt] = 1
        return dicts == dictt

题号26. 删除排序数组中的重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。

代码:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0
        i = 0
        for j in range(len(nums)-1):
            if nums[j] == nums[j+1]:
                continue
            else:
                i += 1
                nums[i] = nums[j+1]
        return i+1            

思路:双指针法
数组完成排序后,我们可以放置两个指针 i i i j j j,其中 i i i 是慢指针,而 j j j 是快指针。只要 n u m s [ i ] = n u m s [ j ] nums[i] = nums[j] nums[i]=nums[j],我们就增加 j j j 以跳过重复项。
当我们遇到 n u m s [ j ] ! = n u m s [ i ] nums[j] != nums[i] nums[j]!=nums[i] 时,跳过重复项的运行已经结束,因此我们必须把它 n u m s [ j ] nums[j] nums[j]的值复制到 n u m s [ i + 1 ] nums[i + 1] nums[i+1]。然后递增 i i i,接着我们将再次重复相同的过程,直到 j j j 到达数组的末尾为止。

题号 27. 移除元素

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。

思路:双指针法

放置两个指针:慢指针 i i i和快指针 j j j,只要 n u m s [ j ] = v a l nums[j] = val nums[j]=val, continue, j + 1 j+1 j+1;
否则, n u m s [ i ] = n u m s [ j ] nums[i] = nums[j] nums[i]=nums[j],并且令 i = i + 1 i=i+1 i=i+1,循环到j遍历所有元素

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i = 0
        for j in range(len(nums)):
            if nums[j] == val:
                continue
            else:
                nums[i] = nums[j]
                i += 1
        return i

题号 35. 搜索插入位置

https://leetcode-cn.com/problems/search-insert-position/
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。

输入: [1,3,5,6], 5
输出: 2

三种思路:
一:二分查找法

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
         low = 0
         high = len(nums)
         while low<high:
             mid = low + (high - low) // 2
             if nums[mid] < target:
                 low = mid + 1
             elif nums[mid] > target:
                 high = mid
             else:
                 return mid
            
         return low

二:for循环

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        for i, num in enumerate(nums):
            if num >= target:
                return i
        return i+1

三:取出所有小于或等于target的元素,组成新列表

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int: 
         left = [i for i in nums if i <= target]
         if left == []:
             return 0
         if left[-1] == target:
             return len(left) - 1
         else:
             return len(left)

题号 38. 报数

报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:

  1. 1
  2. 11
  3. 21
  4. 1211
  5. 111221

1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。

给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。

注意:整数顺序将表示为一个字符串。

我的思路:
利用for循环遍历上一次的字符串,判断下一个是否与前一个元素相同,如果相同则计数,如果不相同则更新新生成的字符串,重置计数

class Solution:
    def countAndSay(self, n: int) -> str:
        if n == 1:
            return '1'
        if n == 2:
            return '11'
        result = '11'
        i = 3
        while i <= n:
            new = ''
            p = result[0]
            count = 0
            for j in range(len(result)):
                if result[j] == p:
                    count += 1
                else:
                    new = new + str(count) + result[j-1]
                    count = 1
                    p = result[j]
            new = new + str(count) + result[j]
            result = new
            i += 1
        return result

题号 53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

  1. 基于动态规划
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        for i in range(1, len(nums)):
            nums[i] = nums[i] + max(nums[i-1], 0)
        return max(nums)  

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        sum = 0
        max_sum = nums[0]
        for i in range(len(nums)):
            sum += nums[i]
            if sum > max_sum:
                max_sum = sum
            if sum < 0:
                sum = 0
        return max_sum     
  1. 基于分治策略

题号 70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

解析:
在这里插入图片描述
在这里插入图片描述
code:

class Solution:
    def climbStairs(self, n: int) -> int:
        d = []
        d.append(0)
        d.append(1)
        d.append(2)
        if n >= 3:
            for i in range(3, n+1):
                d.append(d[i-1] + d[i-2])
                
        return d[n]

数学大法好
在这里插入图片描述
上图中B应该取负号
在这里插入图片描述
code:

class Solution:
    def climbStairs(self, n: int) -> int:
        import math
        sqrt_5 = math.sqrt(5)
        return int((math.pow((1 + sqrt_5)/2, n+1) - math.pow((1 - sqrt_5)/2, n+1))/sqrt_5)

有在GitHub上看到一段非常简洁的代码:

class Solution:
    def climbStairs(self, n: int) -> int:
        from functools import reduce
        return reduce(lambda r, _: (r[1], sum(r)), range(n), (1, 1))[0]

dp递归方程:到达当前楼梯的路径数 = 到达上个楼梯的路径数 + 到达上上个楼梯的路径数
这里用一个元组 r 来储存(当前楼梯路径数,下一层楼梯路径数)
利用 reduce 来代替for循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值