Leetcode(中文)笔记

纵饮孤独 提交于 2020-01-31 05:01:09

Leetcode(中文)笔记

最近在刷leetcode,顺便整理一下笔记,用于自我梳理。目前第一遍仅使用Python。
持续更新中。。。

双指针

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

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
暴力求解:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        i = 0
        while i < len(nums)-1:
            if nums[i] == nums[i+1]:
                nums.pop(i+1)
            else:
                i += 1
        return len(nums)

双指针法:
第一个指针:遍历数组,每遇到nums[j] != nums[i],就说明遇到了新的不同数字,记录之;
第二个指针:每遇到新的不同数字时,执行i += 1, i指针有两个作用:记录数组中不同数字的数量;作为修改数组元素的索引index。
最终,返回i+1即可。

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

27. 移除元素

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
双指针法1:
定义指针j=0
从第一个元素开始遍历,对于num: 判断条件num != val,如果满足,将这个值填入nums[j],并令j += 1,指向下一位置
最后一次j加了1,所以返回长度时无需加1.

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        j = 0
        for num in nums:
            if num != val:
                nums[j] = num
                j += 1
        return j

双指针法2:
定义左指针l=0和右指针r=n *特别注意:*这里右指针r=n,这样可以将很多特例如:[1],1包含在内
执行循环l<r
如果nums[l]==val,则交换nums[l]和nums[r],表示,如果左端值等于val,则和右端交换。并令右端r=r+1,表示这个位置已经放了val,和下一位置交换
若不满足条件,则令左端指向下一元素l=l+1
返回l,这里因为右指针初始化为n,可结合例子,发现i即为最终长度

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        l = 0
        r = len(nums)
        while (r>l):
            if nums[l]==val:
                nums[l], nums[r-1] = nums[r-1], nums[l]
                r -= 1
            else:
                l += 1
        return l

28. 实现 strStr()

实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。当 needle 是空字符串时我们应当返回 0 。
双指针法:
两个指针i和j分别指向haystack和needle串。
每次迭代逐位比较,主要是指针移动的条件判断:
当两个当前字符相等时,i+1,j+1,并判断j是否越界,若越界就找到了,返回结果i-j;否则继续。
当两个当前字符不相等时,i重置到i-j的下一个位置,j重置为0。

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        if len(needle) == 0:
            return 0
        j = 0
        i = 0
        while i < len(haystack):
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            else:
                i = i - j + 1
                j = 0
            if j == len(needle):
                return i - len(needle)
        return -1

88. 合并两个有序数组

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
双指针法:

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        nums = []
        i = 0
        j = 0
        while i<m and j<n:
            if nums1[i] <= nums2[j]:
                nums.append(nums1[i])
                i += 1
            else:
                nums.append(nums2[j])
                j += 1
        if i < m:
            for k in range(i, m):
                nums.append(nums1[k])
        elif j < n:
            for k in range(j, n):
                nums.append(nums2[k])
        nums1[:m+n] = nums[:m+n]

反向双指针法:

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        i = m - 1
        j = n - 1
        k = m + n - 1
        while i>=0 and j>=0:
            if nums1[i] >= nums2[j]:
               nums1[k] = nums1[i]
               k -= 1
               i -= 1
            else:
                nums1[k] = nums2[j]
                k -= 1
                j -= 1
        if j >= 0:
            nums1[:j+1] = nums2[:j+1]

125. 验证回文串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
双指针法:

class Solution:
    def isPalindrome(self, s: str) -> bool:
        list_s = list(s)
        if not list_s:
            return True
        i = 0
        j = len(list_s) - 1
        while i < j:
            if ('0' <= list_s[i] <= '9' or 'a' <= list_s[i] <= 'z' or 'A' <= list_s[i] <= 'Z') and ('0' <= list_s[j] <= '9' or 'a' <= list_s[j] <= 'z' or 'A' <= list_s[j] <= 'Z'):
                if list_s[i].lower() == list_s[j].lower():
                    i += 1
                    j -= 1
                else:
                    return False
            if not ('0' <= list_s[i] <= '9' or 'a' <= list_s[i] <= 'z' or 'A' <= list_s[i] <= 'Z'):
                i += 1
            if not ('0' <= list_s[j] <= '9' or 'a' <= list_s[j] <= 'z' or 'A' <= list_s[j] <= 'Z'):
                j -= 1
        return True

141. 环形链表

给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
双指针法:

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

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        i = head
        j = head
        while j and j.next:
            i = i.next
            j = j.next.next
            if i == j:
                return True
        return False

167. 两数之和 II - 输入有序数组

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
双指针法:

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        i = 0
        j = len(numbers) - 1
        while i<j:
            if numbers[i] + numbers[j] < target:
                i += 1
            elif numbers[i] + numbers[j] > target:
                j -= 1
            else:
                return [i+1,j+1]

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
双指针法:

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        i = 0
        j = 1
        while j<len(nums):
            if nums[i] == 0:
                if nums[j] != 0:
                    nums[i] , nums[j] = nums[j], nums[i]
                    i += 1
                    j += 1
                else:
                    j +=1
            else:
                i += 1
                j += 1
        return nums

双指针法:

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        j = 0
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[i] , nums[j] = nums[j], nums[i]
                j += 1

234. 回文链表

请判断一个链表是否为回文链表。
数组法: 时间复杂度:
使用数组将链表中的值存储起来,然后将数组截半,前半部分数组与后半部分数组的逆序进行逐项对比,判断两个数组是否相等,如果相等则是回文串。如果数组长度为基数,忽略中间的元素。

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

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        linked_list = []
        while head != None:
            linked_list.append(head.val)
            head = head.next
        len_list = len(linked_list)
        half_len = len_list // 2
        if linked_list[:half_len+1] == linked_list[::-1][:half_len+1]:
            return True
        else:
            return False

双指针+翻转法:

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

class Solution(object):
    def isPalindrome(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        # 反转链表,快慢指针,找到链表的中心位置,一个指针跟在慢指针后反转链表
        RHead = None
        if not head or not head.next:
            return True
        else:
            slow = head
            quick = head.next

        while quick and quick.next:
            temp = slow
            slow = slow.next
            quick = quick.next.next
            temp.next = RHead
            RHead = temp
        
        if quick:  # 偶数
            quick = slow.next
            slow.next = RHead
        else:
            quick = slow.next
            slow = RHead

        while quick and slow:
            if quick.val != slow.val:
                return False
            else:
                quick = quick.next
                slow = slow.next
        return True

344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
双指针法:

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        i = 0
        j = len(s)-1
        while i < j:
            s[i], s[j] = s[j], s[i]
            i += 1
            j -= 1

345. 反转字符串中的元音字母

编写一个函数,以字符串作为输入,反转该字符串中的元音字母
双指针法:

class Solution:
    def reverseVowels(self, s: str) -> str:
        Univocalic = ['a','e','i','o','u','A','E','I','O','U']
        s_list = list(s)
        i = 0
        j = len(s_list) - 1
        while i<j:
            if s_list[j] not in Univocalic:
                j -= 1
            elif s_list[i] not in Univocalic:
                i += 1
            else:
                s_list[i], s_list[j] = s_list[j], s_list[i]
                i += 1
                j -= 1
        return "".join(s_list)

350. 两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。
暴力求解:

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        inter_nums = []
        for i in range(len(nums1)):
            j = 0
            while j < len(nums2):
                if nums1[i] == nums2[j]:
                    inter_nums.append(nums1[i])
                    nums2.pop(j)
                    break
                else:
                    j += 1
        return inter_nums

排序+双指针法:

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        inter_nums = []
        nums1.sort()
        nums2.sort()
        i = 0
        j = 0
        while i<len(nums1) and j<len(nums2):
            if nums1[i] == nums2[j]:
                inter_nums.append(nums1[i])
                i+=1
                j+=1
            elif nums1[i] < nums2[j]:
                i += 1
            else:
                j += 1
        return inter_nums

532. 数组中的K-diff数对

给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对。这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字,且两数之差的绝对值是 k.
排序+双指针法: 时间复杂度:
先排序,将符合的数对存到列表中,每次遇到符合条件的数对判断列表中是否已经存在了。最后统计列表长度。

class Solution:
    def findPairs(self, nums: List[int], k: int) -> int:
        nums.sort()
        i = 0
        j = 1
        diff = []
        while i<len(nums) and j<len(nums):
            if i == j:
                j +=1
            elif nums[j] - nums[i] == k:
                if [nums[i], nums[j]] not in diff:
                    diff.append([nums[i], nums[j]])
                i += 1
                j += 1
            elif nums[j] - nums[i] > k:
                i += 1
            else:
                j += 1
        return len(diff)

排序+双指针法:
先排序,当指针j的值减去指针i的值等于k时,存下指针j的值,n+=1,i,j+=1.当指针j的值与缓存中的值相等时j+=1.

class Solution:
    def findPairs(self, nums: List[int], k: int) -> int:
        nums.sort()
        i = 0
        j = 1
        n = 0
        cache = 1e7+1
        while i<len(nums) and j<len(nums):
            if i == j:
                j +=1
            elif nums[j] - nums[i] == k and nums[j] != cache:
                cache = nums[j]
                n += 1
                i += 1
                j += 1
            elif nums[j] - nums[i] > k:
                i += 1
            else:
                j += 1
        return n

哈希或SET法:
两个hash或set(当哈希用)存已访问的数和已发现的k-diff中的较小值

class Solution:
    def findPairs(self, nums: List[int], k: int) -> int:
        if k<0:
            return 0
        dif_nums = set()
        ans = set()
        for num in nums:
            if num-k in dif_nums:
                ans.add(num-k)
            if num+k in dif_nums:
                ans.add(num)
            dif_nums.add(num)
        return len(ans)

844. 比较含退格的字符串

给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
重构字符串法:

class Solution:
    def backspaceCompare(self, S: str, T: str) -> bool:
        list_s = []
        list_t = []
        i = 0
        j = 0
        while i<len(S):
            if S[i] != '#':
                list_s.append(S[i])
            elif list_s:
                list_s.pop()
            i += 1
        while j<len(T):
            if T[j] != '#':
                list_t.append(T[j])
            elif list_t:
                list_t.pop()
            j +=1
        if list_s == list_t:
            return True
        else:
            return False

925. 长按键入

你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。
你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字(其中一些字符可能被长按),那么就返回 True。
双指针法:

class Solution:
    def isLongPressedName(self, name: str, typed: str) -> bool:
        i = 0
        j = 0
        while i < len(name) and j < len(typed):
            if name[i] == typed[j]:
                i += 1
                j += 1
            elif(typed[j] == typed[j-1]):
                j += 1
            else:
                return False
        if i < len(name):
            return False
        else:
            for k in range(j, len(typed)):
                if typed[k] == typed[j-1]:
                    continue
                else:
                    return False
            return True

977. 有序数组的平方

给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
双指针法:

class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        m = 0
        while m < len(A):
            if A[m] < 0:
                m += 1
            else:
                break
        ans = []
        i = m - 1
        j = m
        while i>=0 and j<len(A):
            if A[j] ** 2 < A[i] ** 2:
                ans.append(A[j] ** 2)
                j += 1
            else:
                ans.append(A[i] ** 2)
                i -= 1
        while i>=0:
            ans.append(A[i] ** 2)
            i -= 1
        while j<len(A):
            ans.append(A[j] ** 2)
            j += 1
        return ans

392. 判断子序列

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
双指针法:

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        a = 0
        b = 0
        while a < len(s) and b < len(t):
            if s[a] == t[b]:
                a += 1
                b += 1
            else:
                b += 1
        if a == len(s):
            return True
        else:
            return False

1237. 找出给定方程的正整数解

给出一个函数 f(x, y) 和一个目标结果 z,请你计算方程 f(x,y) == z 所有可能的正整数 数对 x 和 y。
给定函数是严格单调的,也就是说:
f(x, y) < f(x + 1, y)
f(x, y) < f(x, y + 1)
函数接口定义如下:
interface CustomFunction {
public:
// Returns positive integer f(x, y) for any given positive integer x and y.
int f(int x, int y);
};
如果你想自定义测试,你可以输入整数 function_id 和一个目标结果 z 作为输入,其中 function_id 表示一个隐藏函数列表中的一个函数编号,题目只会告诉你列表中的 2 个函数。
你可以将满足条件的 结果数对 按任意顺序返回。
暴力循环:

"""
   This is the custom function interface.
   You should not implement it, or speculate about its implementation
   class CustomFunction:
       # Returns f(x, y) for any given positive integers x and y.
       # Note that f(x, y) is increasing with respect to both x and y.
       # i.e. f(x, y) < f(x + 1, y), f(x, y) < f(x, y + 1)
       def f(self, x, y):
  
"""
class Solution:
    def findSolution(self, customfunction: 'CustomFunction', z: int) -> List[List[int]]:
        ans = []
        for i in range(1, z+1):
            for j in range(1, z+1):
                if customfunction.f(i, j) == z:
                    ans.append([i,j])
        return ans

双指针法:

"""
   This is the custom function interface.
   You should not implement it, or speculate about its implementation
   class CustomFunction:
       # Returns f(x, y) for any given positive integers x and y.
       # Note that f(x, y) is increasing with respect to both x and y.
       # i.e. f(x, y) < f(x + 1, y), f(x, y) < f(x, y + 1)
       def f(self, x, y):
  
"""
class Solution:
    def findSolution(self, customfunction: 'CustomFunction', z: int) -> List[List[int]]:
        x = 1
        y = z
        f = customfunction.f
        ans = []
        while(x<=z and y>=1):
            if f(x,y) == z:
                ans.append([x,y])
                x+=1
                y-=1
            elif f(x,y)>z:
                y-=1
            else:
                x+=1
        return ans


"""
   This is the custom function interface.
   You should not implement it, or speculate about its implementation
   class CustomFunction:
       # Returns f(x, y) for any given positive integers x and y.
       # Note that f(x, y) is increasing with respect to both x and y.
       # i.e. f(x, y) < f(x + 1, y), f(x, y) < f(x, y + 1)
       def f(self, x, y):
  
"""
class Solution:
    def findSolution(self, customfunction: 'CustomFunction', z: int) -> List[List[int]]:
        ans = []
        for x in range(1,1001):
            if customfunction.f(x,1)<=z and customfunction.f(x,1000)>=z:
                #bi search y
                i = 1
                j = 1000
                while i<=j:
                    m = (i+j)//2
                    if customfunction.f(x,m)>z:
                        j = m-1
                    elif customfunction.f(x,m)<z:
                        i = m+1
                    else:
                        ans.append([x, m])
                        break
        return ans

哈希表

1.两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
暴力法:

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

字典模拟Hash:

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        _dict = {}
        for i, m in enumerate(nums):
            _dict[m] = i
        for i, n in enumerate(nums):
            j = _dict.get(target - n)
            if j != i and j is not None:
                return [i,j]

一遍字典模拟Hash:

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        _dict = {}
        for i, m in enumerate(nums):
            if _dict.get(target - m) is not None:
                return [i, _dict.get(target-m)]
            _dict[m] = i

349. 两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。
暴力求解法:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        ans = []
        for i in range(len(nums1)):
            if nums1[i] in nums2 and nums1[i] not in ans:
                ans.append(nums1[i])
        return ans

转set法:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1_set = set(nums1)
        return nums1_set.intersection(set(nums2))

二分查找法

35. 搜索插入位置

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
直接遍历法:

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

二分查找法:

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

69. x 的平方根

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去
二分查找法:

class Solution:
    def mySqrt(self, x: int) -> int:
        left = 0
        right = x
        while(left <= right):
            mid = (left + right) // 2
            if (mid*mid == x):
                return mid
            elif(mid*mid < x):
                if((mid+1)*(mid+1)>x):
                    return mid
                else:
                    left = mid + 1
            else:
                right = mid - 1

278. 第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
二分查找法:

# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):

class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        left = 0
        right = n
        while left <= right:
            mid = (left + right) // 2
            if isBadVersion(mid) == False:
                left = mid + 1
            else:
                if isBadVersion(mid - 1) == False:
                    return mid
                else:
                    right = mid - 1

367. 有效的完全平方数

给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。
说明:不要使用任何内置的库函数,如 sqrt。
二分查找法:

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left = 0
        right = num
        while left < right:
            mid = (left + right) // 2
            if mid * mid < num:
                left = mid + 1
            elif mid * mid == num:
                return True
            else:
                right = mid - 1
        if left * left == num:
            return True
        else:
            return False

374. 猜数字大小

我们正在玩一个猜数字游戏。 游戏规则如下:
我从 1 到 n 选择一个数字。 你需要猜我选择了哪个数字。
每次你猜错了,我会告诉你这个数字是大了还是小了。
你调用一个预先定义好的接口 guess(int num),它会返回 3 个可能的结果(-1,1 或 0):
-1 : 我的数字比较小
1 : 我的数字比较大
0 : 恭喜!你猜对了!
二分查找法:

# The guess API is already defined for you.
# @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
# def guess(num: int) -> int:

class Solution:
    def guessNumber(self, n: int) -> int:
        left = 1
        right = n
        while left <= right:
            mid = (left + right) // 2
            if guess(mid) == -1:
                right = mid - 1
            elif guess(mid) == 1:
                left = mid + 1
            else:
                return mid

441. 排列硬币

你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。
给定一个数字 n,找出可形成完整阶梯行的总行数。
n 是一个非负整数,并且在32位有符号整型的范围内。
直接遍历法:

class Solution:
    def arrangeCoins(self, n: int) -> int:
        sum_i = 0
        for i in range(n+1):
            sum_i += i
            if sum_i == n or (sum_i < n and sum_i + i + 1 > n):
                return i 

二分查找法:

class Solution:
    def arrangeCoins(self, n: int) -> int:
        left = 0
        right = n
        while(left<=right):
            mid = (left + right) // 2
            sum_mid = (1+mid)*(mid) / 2
            if (sum_mid < n):
                sum_mid = (1+mid+1)*(mid+1) / 2
                if(sum_mid > n):
                    return mid
                else:
                    left = mid + 1
            elif (sum_mid > n):
                right = mid - 1
            else:
                return mid

直接求解法:

from math import sqrt, floor
class Solution:
    def arrangeCoins(self, n: int) -> int:
        return floor( sqrt(1/4+2*n)-1/2 )

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
二分查找法:

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

744. 寻找比目标字母大的最小字母

给定一个只包含小写字母的有序数组letters 和一个目标字母 target,寻找有序数组里面比目标字母大的最小字母。
数组里字母的顺序是循环的。举个例子,如果目标字母target = ‘z’ 并且有序数组为 letters = [‘a’, ‘b’],则答案返回 ‘a’。
二分查找法:

class Solution:
    def nextGreatestLetter(self, letters: List[str], target: str) -> str:
        left = 0
        right = len(letters) - 1
        while(left <= right):
            mid = (left + right) // 2
            if(ord(letters[mid]) <= ord(target)):
                if(mid<len(letters)-1):
                    if(ord(letters[mid+1]) > ord(target)):
                        return letters[mid+1]
                    else:
                        left = mid + 1
                else:
                    return letters[0]
            else:
                if(mid == 0):
                    return letters[mid]
                else:
                    if(ord(letters[mid-1])<ord(target)):
                        return letters[mid]
                    else:
                        right = mid - 1

852. 山脉数组的峰顶索引

我们把符合下列属性的数组 A 称作山脉:
A.length >= 3
存在 0 < i < A.length - 1 使得A[0] < A[1] < … A[i-1] < A[i] > A[i+1] > … > A[A.length - 1]
给定一个确定为山脉的数组,返回任何满足 A[0] < A[1] < … A[i-1] < A[i] > A[i+1] > … > A[A.length - 1] 的 i 的值。
数组最大值索引:

class Solution:
    def peakIndexInMountainArray(self, A: List[int]) -> int:
        return A.index(max(A))

直接遍历法:

class Solution:
    def peakIndexInMountainArray(self, A: List[int]) -> int:
        for i in range(1, len(A)-1):
            if (A[i] > A[i-1]) and (A[i] > A[i+1]):
                return i

二分查找法:

class Solution:
    def peakIndexInMountainArray(self, A: List[int]) -> int:
        left = 0
        right = len(A) - 1
        while(left < right):
            mid = (left + right) // 2
            if A[mid] < A[mid+1]:
                left = mid + 1
            else:
                right = mid
        return left 

475. 供暖器

冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
现在,给出位于一条水平线上的房屋和供暖器的位置,找到可以覆盖所有房屋的最小加热半径。
所以,你的输入将会是房屋和供暖器的位置。你将输出供暖器的最小加热半径。
说明:
给出的房屋和供暖器的数目是非负数且不会超过 25000。
给出的房屋和供暖器的位置均是非负数且不会超过10^9。
只要房屋位于供暖器的半径内(包括在边缘上),它就可以得到供暖。
所有供暖器都遵循你的半径标准,加热的半径也一样。
二分查找法:

class Solution:
    def findRadius(self, houses: List[int], heaters: List[int]) -> int:
        ans = []
        houses.sort()
        heaters.sort()
        for house in houses:
            left = 0
            right = len(heaters) - 1
            while(left<right):
                mid = (left + right)//2
                if heaters[mid] < house:
                    left = mid + 1
                else:
                    right = mid
            if heaters[left] == house:
                ans.append(0)
            elif heaters[left] < house:
                ans.append(house - heaters[left])
            elif left != 0:
                ans.append(min((house - heaters[left-1]),(heaters[left] - house)))
            else:
                ans.append(heaters[left] - house)
        return max(ans)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!