Python刷leetcode的一些语法笔记

 


1. 使用列表解析的方法创建矩阵

leetcode867矩阵转置:先创建一个0矩阵,在赋值A[j][i]

列表解析创建:

result = [[0 for i in range(len(A))] for j in range(len(A[0]))]
#注意行数和列数是与原矩阵相反的

传统创建:

result = []
for i in range(len(A[0])):
    list = []
    for j in range(len(A)):
        list.append(0)
    result.append(list)

两种列表解析:

1.[expression for iter_val in iterable]

2.[expression for iter_val in iterable if cond_expr]  #仅在符合条件是加入该元素,并不会用0填充

L = [i**2 for i in range(1,11) if i**2 >50]
print(L)

输出:
[64, 81, 100]

2.内置zip函数用法

该题也可用Python自带zip函数进行翻转行与列

class Solution:
    def transpose(self, A: List[List[int]]) -> List[List[int]]:
        return [list(i) for i in zip(*A)]

关于zip函数的详细用法:https://www.cnblogs.com/frydsh/archive/2012/07/10/2585370.html

zip函数顾名思义:将元组或列表(可以同时处理两种数据结构)一一对应的元素压缩成一个元组

*A可以理解为指针,将矩阵的每一行分开交给zip函数处理

list(i)为将zip函数返回的元组转为列表

3.字典dict(哈希表)20200915

心得 : 哈希表适合处理数组中的有关重复元素的问题。

leetcode面试题 17.10. 主要元素:用for循环遍历nums中每一个元素:1. 每遇到一个新元素则加入字典中,2. 每遇到一个在字典中的元素则将对应元素的值加1

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        hashmap = dict()
        count = 0
        for elem in nums:
            if elem not in hashmap:
                hashmap[elem] = 1
            else:
                hashmap[elem] += 1
        for key, hash_elem in hashmap.items(): #以列表返回可遍历的(键, 值) 元组数组
            if hash_elem >= len(nums) / 2:
                return key
        return -1

注意:1. 采用in来检查字典中是否存在已有元素, 2. 使用items函数来获取字典中的键与值

 

leetcode219. 存在重复元素 II

该题Python硬做(两个for循环)会超时,需要使用哈希表(字典)的思想。

1. 将对应的数当做键存入字典中,并将该键值置为当前元素下标(关键)。

2. 之后每次有重复的元素(if in 判断)则判断其间隔是否超过k,超过即返回True。

3. 每次有重复元素,但超出了k也要更新字典中的下标(不通过的一个小原因)。

class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        dict = {}
        flag = False
        for i in range(len(nums)):
            if nums[i] not in dict:
                dict[nums[i]] = i
            elif i - dict[nums[i]] <= k:
                flag = True
                break
            else:
                dict[nums[i]] = i
        return flag

评论中简化的代码,可以学习一下:

class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        dict = {}
        for i in range(len(nums)):
            if nums[i] in dict and i - dict[nums[i]] <= k:
                return True
            dict[nums[i]] = i
        return False

4. Set()

功能:用于去重,创建一个无重复元素的,无序的集合(不是元组,元组是(),集合是{})

详细用法:https://blog.csdn.net/cadi2011/article/details/85097375

利用先去重(使用set())再做统计(列表.count(某一元素))的方法来实现leetcode面试题 17.10.

代码1:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        nums1 = list(set(nums))
        res = -1
        for elem in nums1:
            if nums.count(elem) > int(len(nums) / 2):
                res = elem
                break
        return res

代码2:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        nums1 = list(set(nums))
        for elem in nums1:
            if nums.count(elem) > int(len(nums) / 2):
                return elem
        return -1

代码1时间与空间的消耗都更少,有时间可以思考一下为啥

leetcode面试题 17.10.的排序解法:排序后前一半与后一半一一对应,如果有元素相同,则该元素个数必然len(nums)/ 2

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        half = int(len(nums) / 2) #int不是四舍五入,而是截断(向下取整)
        res = -1
        nums.sort()
        for i in range(0, len(nums) - half):
            if nums[i] == nums[i + half]:
                res = nums[i]
                break
        return res

为啥range(0, len(nums) - half)没有越界?

因为:例:range(0,2)为0,1不包括2

5. 双指针20200916

用法:将两个有序数组合并为一个有序数组

leetcode997有序数的平方

class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        index = 0
        for i in range(len(A)):
            if A[i] >= 0:
                index = i
                break
        positives = [x**2 for x in A[index:]]
        negatives = [y**2 for y in A[:index]]
        negatives.reverse()

        if positives == []:
            return negatives
        elif negatives == []:
            return positives
        
        res = []
        p = 0
        n = 0
        while p < len(positives) or n < len(negatives):
            if positives[p] <= negatives[n]:
                res.append(positives[p])
                p += 1
            else:
                res.append(negatives[n])
                n += 1
            if p == len(positives) and n < len(negatives):
                return res + negatives[n:]    
            elif p < len(positives) and n == len(negatives):
                return res + positives[p:]

注意:1. 利用for循环来初始化一个列表 2. 双指针法的结束条件为其中一个数组的指针指向最后一个元素(并不是看哪个数组长,且不存在两个数组的指针同时指向最后一个元素的情况) 3. reverse()可将列表逆置

 

 学会在草稿纸上分析,不要光脑袋想 20200918打卡 leetcode628. 三个数的最大乘积

20200919打卡 leetcode 1550. 存在连续三个奇数的数组 219. 存在重复元素 II

6. 贪心算法

leetcode605. 种花问题 https://leetcode-cn.com/problems/can-place-flowers/

思路:利用贪心的思想,从前到后依次判断当前位置和前后两个位置是否为0,是,则可以种花,将该位置置为1。继续向后扫描重复。

两种情况:1. 在第一个和最后一个位置,只需判断当前位置和前后其中一个位置;

2. 需判断3个位置

优化:先在前后位置补0,则可从补完的数组的第二个位置开始且只需考虑一种情况

class Solution:
    def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
        num = 0
        flag= False
        new_flowerbed = [0] + flowerbed + [0]
        for i in range(1, len(new_flowerbed) - 1):
            if new_flowerbed[i] == 0 and new_flowerbed[i - 1] == 0 and new_flowerbed[i + 1] == 0:
                new_flowerbed[i] = 1
                num += 1
        if num >= n:
            flag = True
        return flag

7. 使用sum()来计算列表元素和

20200920leetcode5503. 所有奇数长度子数组的和 https://leetcode-cn.com/problems/sum-of-all-odd-length-subarrays/

class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        sum1 = 0
        for gap in range(1, len(arr) + 1, 2):
            for i in range(len(arr) - gap + 1):
                    sum1 += sum(arr[i : i + gap])
        return sum1

注意:1. sum(arr[i : i + gap])的用法。

2. for循环中步长的写法,for gap in range(1, len(arr) + 1, 2),注意len(arr) + 1如果是奇数是不包含在内的。

8. 前缀和(python可直接使用sum()计算,求前缀和作差运行时间更短)

前缀和:创建一个列表每一个元素都为对应列表之前元素的和。

例:[1,4,5 ,2,6 ]对应的前缀和列表为[1,5,10,12,18], 其初始化的方法为前缀和列表的当前元素前缀和列表中的上一个元素加上原始列表的当前元素。

20200920leetcode5503. 所有奇数长度子数组的和 https://leetcode-cn.com/problems/sum-of-all-odd-length-subarrays/

由于需要求连续序列的和,可以想到创建前缀和列表,列表两个位置作差即可得到两个位置中间段序列的和。

class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        pre = [0]
        for elem in arr:
            pre.append(pre[-1] + elem)
        sum1 = 0
        for gap in range(1, len(arr) + 1, 2):
            for i in range(len(arr) - gap + 1):
                    sum1 += pre[i + gap] - pre[i]
        return sum1

注意:1. 使用list[-1]可以直接访问列表的最后一个元素

2. 前缀和列表的第一个元素必须是0,这样才可以直接进行相减(下标刚好对应)

 

☆20200929 leetcode 1074. 元素和为目标值的子矩阵数量 https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/

该题为二维前缀和,有两种解法:
1. 算出整个矩阵的前缀和(预处理),再通过矩阵相加减来计算出子矩阵的元素和(需要四重循环,两层控制行开始,行结束,两层控制列开始,列结束)

2. 先计算出每一列的列前缀和(预处理),再用两个for循环来固定行的开始与末尾,在其中每次从左到右算出当前列的前缀和temp并存入字典中。(等于就是利用存放在字典里,再去查找的方式,少用了一层循环)

两种情况结果符合题目要求:

(1)当前temp == target直接符合要求,res += 1;

(2)temp_current - target = temp_previous ,即temp_current - temp_previous = target(中间部分列组成的子矩阵的元素和符合target)

3.将当前列的前缀和存入字典d中。

class Solution:
    def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
        row, col = len(matrix), len(matrix[0])#行是矩阵里有多少个列表,列是列表里有多少个元素
        pre_sum = [[0] * col for i in range(row)]
        for i in range(col):#先计算每一列的前缀和,因为下面的思路是固定行的开始与结尾,逐列相加算出当前列的前缀和并存入字典中
            temp = 0
            for j in range(row):
                temp += matrix[j][i]
                pre_sum[j][i] = temp
        res = 0
        for start_r in range(row):
            for end_r in range(start_r, row):
                d = collections.defaultdict(int)
                temp = 0
                for c in range(col):
                    pre = 0 if start_r - 1 < 0 else pre_sum[start_r - 1][c]
                    temp += pre_sum[end_r][c] - pre #这里累加是计算当前固定了开始的行与开始的列后,从左到右每一次列的前缀和
                    if temp == target:
                        res += 1
                    res += d[temp - target]#temp_current - target = temp_previous可以看成现在的temp减之前的temp(等于是夹在中间的矩阵)符合target
                    d[temp] += 1#将当前前缀和存入字典中
                    #上面两条顺序不能反,当target == 0时会加重复
        return res

9. 二分查找

leetcode 1552. 两球之间的磁力 https://leetcode-cn.com/problems/magnetic-force-between-two-balls/

class Solution:
    def maxDistance(self, position: List[int], m: int) -> int:
        position.sort()
        left = min([ position[i + 1] - position[i] for i in range(len(position) - 1)])
        #相邻篮子最小的那个距离
        right = position[-1] - position[0]
        #第一个和最后一个篮子的距离

        def check(diff):
            count = 0
            i, j = 0, 0
            while j < len(position):
                while j < len(position) and position[j] - position[i] < diff:
                    j += 1 
                    #找到一个与前一个位置距离大于当前check的值的位置,至于后面的距离是否符合之后处理
                if j < len(position):
                    count += 1
                i = j
                    #寻找下一个
            return count >= m - 1
            #这里是处理上面留下的之后的距离是否也大于检验值的问题,举个例子,如果count = 2,则说明除了最后一个球,中间还可以放一个球,这时总共可以放3个球也就是count = m - 1。count当然是越大说明可以放得球越多,也就说明当前check的值偏小,需要加大,也就是left = mid + 1。反之,count < m - 1,则说明以当前的两球最大间隔来放置放不下那么多球,这时候需要减小间隔,即right = mid - 1。   
        while left <= right:
            mid = (left + right) // 2
            if check(mid):
                left = mid + 1
            else:
                right = mid - 1
        return left - 1

我是真的菜...这题想了好久没弄出来,然后看答案也看了好久才弄懂。

思路:贪心策略,

1. 先在第一个位置放置一个球,

2. 给定一个所有球之间最大化的最小间隔diff,每次放置一个球并使得这个球满足于前一个球的间隔大于等于diff

3. 每次计数,count初始为1(第一个球一定在第一个位置,这里与代码不一样,这样更好理解),

当count >=m时,说明该diff符合条件,可以继续试更大的diff

当count<m时,说明该diff不足以放置放置m个球,需要减小diff

二分查找只是优化的一种手段,不是该题的思路

注意:1. 二分查找判断后对查找范围的操作,每次不是继续以mid为基准,而是需要+1或-1。

2. 为什么返回left - 1?因为当最后一次mid符合条件时,该mid对应的值为left - 1。之后循环继续会先mid = (left + right) // 2,这里会改变mid的值,所以不能直接返回mid。再进入else,改变right的值,然后判断while left <= right,这时候right + 1= left 跳出循环,所以直接返回right也可以。不过这样绕了一圈,直接返回left - 1会比较好理解。

10. 滑动窗口+单调栈

leetcode1438. 绝对差不超过限制的最长连续子数组 https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/

1. 暴力法 (超时):模拟整个流程

class Solution:
    def longestSubarray(self, nums: List[int], limit: int) -> int:
        res = 0
        if max(nums) == min(nums):
            return len(nums)
        for i in range(len(nums)):
            max_len = 0
            for j in range(i + 1, len(nums)):
                max_num = max(nums[i : j + 1])
                min_num = min(nums[i : j + 1]) 
                if max_num - min_num <= limit:
                    if j - i > max_len:
                        max_len = j - i
                else:
                    break
            res = max_len if max_len > res else res
        return res + 1

2. 采用两个单调栈来获取当前窗口的最大与最小值: 好处是对于滑动窗口,不需要每次都花O(n)的时间去寻找当前窗口的最值,而是可以在整体O(n)的时间得到每次的最值。(不是单次的O(n),注意理解一下)

1. 使用两个单调栈,一个为升序,一个为降序。分别在栈底得到最小值与最大值。栈中存放值与在nums中的位置

2. 用for循环控制窗口的尾部,头部在窗口中的最大值与最小值的差值大于limit时向后移动,并且移动单调栈的栈底指针使得窗口外的元素不在栈中。

3. 对栈的操作:以升序栈为例,当当前元素比栈底元素小时,弹出栈顶元素,直到栈顶元素比当前元素大,这时候入栈。这样就可以保证栈顶元素一定是最小的元素。

class Solution:
    def longestSubarray(self, nums: List[int], limit: int) -> int:
        # 栈底维护了最值,栈顶维护了窗口终点

        ascend, descend = [], [] # 维护一个最小值栈,一个最大值栈
        a, d = 0, 0 # 队首下标
        t = 0 # 窗口起始点
        res = 0

        for i in range(len(nums)): # i为窗口终止点,利用循环滑动终止点
            temp = nums[i] # 保存终止点对应的值

            # 更新最小值
            while len(ascend) > a and temp < ascend[-1][0]: # 与栈顶值对比
                ascend.pop() # 弹出
            ascend.append((temp, i)) # 记录终点值与下标
            
            # 更新最大值
            while len(descend) > d and temp > descend[-1][0]: # 与栈顶值对比
                descend.pop() # 弹出
            descend.append((temp, i)) # 记录终点值与下标

            while descend[d][0] - ascend[a][0] > limit: # 最值之差大于limit出发滑动条件
                t += 1 # 起始点滑动
                if ascend[a][1] < t: # 如果窗口起点在最小值索引右侧,需要舍弃此时的最小值
                    a += 1
                if descend[d][1] < t: # 如果窗口起点在最大值索引右侧,需要舍弃此时的最大值
                    d += 1
            
            res = max(res, i-t+1) # 更新最大长度

        return res

11. 第k小数以及用该方法寻找中位数

leetcode 4. 寻找两个正序数组的中位数 https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

在两个有序数组中找第k小数的原理:

1. 取每个数组中k // 2小的数,比较nums1[k // 2]和nums2[k // 2],更小的那一个对应的数组的前k // 2个数一定小于第k个数

2. 这时问题转化成在新的两个数组中找第k - k // 2个数

3. 直到k == 1,得到结果

注意:在第1步中的粗体部分可以用反证法证明。若对应的数组的前k // 2个数存在大于第k小的数,由于是有序数组,则另第k // 2个数大于第k小的数,则另一个数组第k // 2个数也大于第k小的数。则此时存在2 + len(nums1) + len(nums2) - k个比第k的元素大的元素。显然2 + len(nums1) + len(nums2) - k + k != len(nums1) + len(nums2)。

也可以通过证明比较小k  // 2位置大的数,多余len(nums1) + len(nums2) - k,如下图:

递归代码:

def find_k(nums1, nums2, k):
    if len(nums1) < len(nums2):
        nums1, nums2 = nums2, nums1
    if len(nums2) == 0:
        return nums1[k - 1]
    if k == 1:
        return min(nums1[0], nums2[0])
    t = min(k // 2, len(nums2))
    if nums1[t - 1] > nums2[t - 1]:
        return find_k(nums1, nums2[t : ], k -t)
    else:
        return find_k(nums1[t : ], nums2, k -t)

中位数题解: 处理中位数时可以用以下方法表示中位数的位置,这样可以统一处理奇数长度和偶数长度的数组:

令 k1 = ( len(nums1) + len(nums2) + 1 ) // 2,令 k2 = ( len(nums1) + len(nums2) + 2 ) // 2

例:长度为10时,k1 = 5, k2 = 6;长度为9时,k1 = k2 =5

注意:这里不是下标,是第k小的数

中位数则为第k1小的数加第k2小的数之和除二。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        k1 = (len(nums1) + len(nums2) + 1) // 2
        k2 = (len(nums1) + len(nums2) + 2) // 2

        def find_k(nums1, nums2, k):
            if len(nums1) < len(nums2):
                nums1, nums2 = nums2, nums1#确保nums1长于nums2
            if len(nums2) == 0:
                return nums1[k - 1]#可能nums2提前被全部剔除,所以直接返回nums1中当前第k小元素
            if k == 1:
                return min(nums1[0], nums2[0])#两边都在剔除比第k小的数小的元素,不知道最后是那边,所以去两个数组第一个位置的最小值
            t = min(k // 2, len(nums2))#因为较短的num2可能没那么多元素可以剔除,所以取两者较小值防止溢出
            if nums1[t - 1] < nums2[t - 1]:#这里注意下标减1
                return find_k(nums1[t : ], nums2, k - t)#剔除了t个比第k小数小的元素,所以继续寻找第k-t小数
            else:
                return find_k(nums1, nums2[t : ], k - t)
                
        return (find_k(nums1, nums2, k1) + find_k(nums1, nums2, k2)) / 2

12. 动态规划 ☆

20200930leetcode 53. 最大子序和 https://leetcode-cn.com/problems/maximum-subarray/

放国庆了...好浮躁...不想刷题,动态规划还不太熟,以前学的都差不多忘完了,今天刷个简单题意思一下,过几天再研究

思路:从第二个元素开始,每次都有两个状态可以选择:

1. 当该元素前的最大和为正nums[i - 1] > 0,当前元素加上该元素前的最大和; 2. 当该元素前的最大和为负nums[i - 1] < 0,仅保留当前元素。

处理完后的新nums的每一个位置都保存着当前位置前的最大子序和,此时返回max(nums)即可

☆该题还可以用分治法做,之后要注意研究一下

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        for i in range(1, len(nums)):
            nums[i] = max(nums[i] + nums[i - 1], nums[i])
        return max(nums)

20201009 学习动态规划

 学习记录:https://blog.csdn.net/skq990828/article/details/108972396

用于打卡记录:

20200921 leetcode832. 翻转图像 https://leetcode-cn.com/problems/flipping-an-image/

1. 暴力法 :按照题目的流程走一遍,注意python中可以用if else来替代c中的三元表达式?:

class Solution:
    def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
        for list1 in A:
            for i in range(int(len(list1) / 2)):
                list1[i], list1[len(list1) - i - 1] = list1[len(list1) - i - 1], list1[i]
            for i in range(len(list1)):
                list1[i] = 0 if list1[i] == 1 else 1
        return A    

2. 双指针巧解  :两个指针从前后同时进行扫描,有两种情况

(1)当分别所指元素不同时,先水平翻转再01互换后实际上两个位置的元素维持不动

(2)当分别所指元素相同或为最中间元素时,只需将对应位置元素0变1,1变0

class Solution:
    def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
        for list1 in A:
            for i in range(int((len(list1) + 1) / 2)):
                if list1[i] == list1[len(list1) - i - 1]:
                    list1[i], list1[len(list1) - i - 1] = 1 - list1[i], 1 - list1[len(list1) - i - 1]
        return A    

20200922 leetcode1275. 找出井字棋的获胜者 https://leetcode-cn.com/problems/find-winner-on-a-tic-tac-toe-game/

A或B赢:分别将A B两种棋子放入两个列表中分别分析

对列表中任意两个位置满足以下则达成赢:
1.横坐标之和为偶数,纵坐标之和为偶数(保证可以在一条直线的两端)

2.两个位置的横纵坐标分别相加除二(两点的中间位置)后对应位置存在于列表中

未下完:len(moves) < 9,且未决出胜负

平局:len(moves) == 9,即棋盘下满

class Solution:
    def tictactoe(self, moves: List[List[int]]) -> str:
        A = []
        B = []
        for i in range(len(moves)):
            if i % 2 == 0:
                A.append(moves[i])
            else:
                B.append(moves[i])
        if len(moves) % 2 != 0: 
            for i in range(len(A)):
                j = i + 1
                while j < len(A):
                    if (A[i][0] + A[j][0]) % 2 == 0 and (A[i][1] + A[j][1]) % 2 == 0 and [(A[i][0] + A[j][0]) / 2, (A[i][1] + A[j][1]) / 2] in A:
                        return "A"
                    j += 1
        else:
            for i in range(len(B)):
                j = i + 1
                while j < len(B):
                    if (B[i][0] + B[j][0]) % 2 == 0 and (B[i][1] + B[j][1]) % 2 == 0 and [(B[i][0] + B[j][0]) / 2, (B[i][1] + B[j][1]) / 2] in B:
                        return "B"
                    j += 1  
        if len(moves) == 9:
            return "Draw"
        if len(moves) < 9:
            return "Pending"

20200923 leetcode1476. 子矩形查询

对类的操作,注意以下几点:1. 不能对self直接进行操作,只能用self.xx对其成员变量进行访问和操作。 2. 该题的成员变量是自己在初始化函数中定义  3. 注意对range后一个位置进行加一,否则会少修改一行或一列

lass SubrectangleQueries:

    def __init__(self, rectangle: List[List[int]]):
        self.rect = rectangle

    def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
        for i in range(row1, row2 + 1):
            for j in range(col1, col2 + 1):
                self.rect[i][j] = newValue

    def getValue(self, row: int, col: int) -> int:
        return self.rect[row][col]



# Your SubrectangleQueries object will be instantiated and called as such:
# obj = SubrectangleQueries(rectangle)
# obj.updateSubrectangle(row1,col1,row2,col2,newValue)
# param_2 = obj.getValue(row,col)

大佬的做法(省时):设置一个update列表存储更新,而不是实时更新

由于更新时如果数据量较大用两个循环时间消耗会非常多,所以干脆不每次都进行更新,而是在成员变量中设置一个update列表用于存储每一次的更新。在查询时若发现所要查询的元素在该update列表中,即row1 <= row <= row2 and col1<= col <= col2,则返回update中该位置的值否则返回原矩阵中的值

class SubrectangleQueries:

    def __init__(self, rectangle: List[List[int]]):
        self.data = rectangle
        self.update = []

    def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
        self.update.append((row1, col1, row2, col2, newValue))

    def getValue(self, row: int, col: int) -> int:
        res = None
        for i in range(len(self.update)-1, -1, -1):
            row1,col1,row2,col2, val = self.update[i]
            if row1 <= row <= row2 and col1<= col <= col2:
                res = val
                break
        
        return res if res else self.data[row][col]

 20200924 leetcode1535. 找出数组游戏的赢家 https://leetcode-cn.com/problems/find-the-winner-of-an-array-game/

class Solution:
    def getWinner(self, arr: List[int], k: int) -> int:
        if k >= len(arr)-1: return max(arr)
        count = 0
        point = 1
        while point < len(arr) and count < k:
            if arr[0] >= arr[point]:
                count += 1
            else:
                arr[0] = arr[point]
                count = 1
            point += 1
        return arr[0]

注意:1. 先处理极端情况可以大幅减少不必要的时间空间消耗,如该题在扫描一遍后arr[0]一定是最大值,即游戏赢家。所以当扫描完一遍后直接返回arr[0]即可。

2. max(arr)可以直接得到列表中最大值,当k >= len(arr)-1直接返回max(arr)即可。

20200927 leetcode228. 汇总区间 https://leetcode-cn.com/problems/summary-ranges/ 双指针 滑动窗口

思路:贪心原理

1. 开始前指针pre和后指针last都指向第一个元素,last开始后移直到下一个元素不再连续,将结果放入res中

2. 将pre与last重新指向那个不连续的元素,继续上述操作直到last指向倒数第二个元素(最后一个元素由于后面没有可比较的,需要单独处理)

注意:1. 有两种输出的形式,第一种为pre == last : (str(nums[pre]) + "->" + str(nums[last]),第二种为pre != last : str(nums[pre])

2. 需要单独处理nums的最后一个元素,因为当最后一个元素与其前一个元素不连续时,再进入下一轮循环last和pre都指向最后一个元素,而不再有last+1与其比较,所以需要单独处理。

class Solution:
    def summaryRanges(self, nums: List[int]) -> List[str]:
        pre = 0
        last = 0
        res = []
        while pre <= last and last < len(nums):
            if pre == len(nums) - 1:
                res.append(str(nums[pre]))
                break
            if last < len(nums) - 1 and nums[last] + 1 == nums[last + 1]:
                last += 1
            elif pre != last:
                res.append(str(nums[pre]) + "->" + str(nums[last]))
                pre = last + 1
                last = pre
            else:
                res.append(str(nums[pre]))
                pre = last + 1
                last = pre
        return res

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值