Bootstrap

【python】Leetcode(primer)

在这里插入图片描述

(2019.7.26)不断更新中……



1217. 玩筹码

数轴上放置了一些筹码,每个筹码的位置存在数组 chips 当中。

你可以对 任何筹码 执行下面两种操作之一(不限操作次数,0 次也可以):

将第 i 个筹码向左或者右移动 2 个单位,代价为 0。
将第 i 个筹码向左或者右移动 1 个单位,代价为 1。
最开始的时候,同一位置上也可能放着两个或者更多的筹码。

返回将所有筹码移动到同一位置(任意位置)上所需要的最小代价。

示例 1:

输入:chips = [1,2,3]
输出:1
解释:第二个筹码移动到位置三的代价是 1,第一个筹码移动到位置三的代价是 0,总代价为 1。
示例 2:

输入:chips = [2,2,2,3,3]
输出:2
解释:第四和第五个筹码移动到位置二的代价都是 1,所以最小总代价为 2。

提示:

1 <= chips.length <= 100
1 <= chips[i] <= 10^9


一开始想着是往众数还是平均数来着,结果……

移动 1 下,代价 1,也即奇变偶,偶变奇代价为 1
移动 2 下,代价 0,奇偶不变代价为 0

所有数往一个位置移动,说白了,所有数字通过 ± 1 ± 2 变成一样

最终一样的数不是奇数就是偶数,

假如最终的数为奇数,则原始数组中,所有奇数变成该数字时代价为 0,每个偶数变成该数字时代价为 1,此时统计原数组中偶数的个数即可

假如最终的数为偶数,则原始数组中,所有偶数变成该数字时代价为 0,每个奇数变成该数字时代价为 1,此时统计原数组中奇数的个数即可

综合上述两种情况,最小代价就是原数组中奇数数量和偶数数量中较小的那个

class Solution(object):
    def minCostToMoveChips(self, position):
        """
        :type position: List[int]
        :rtype: int
        """
        odd = 0
        even = 0
        
        for i in position:
            if i % 2 == 0:
                even += 1
            else:
                odd += 1
        return min(odd,even)

977. 有序数组的平方

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

  • 示例 1:
    输入:[-4,-1,0,3,10]
    输出:[0,1,9,16,100]

  • 示例 2:
    输入:[-7,-3,2,3,11]
    输出:[4,9,9,49,121]

  • 提示:
    1 <= A.length <= 10000
    -10000 <= A[i] <= 10000
    A 已按非递减顺序排序。

先忽略掉顺序,用最暴力的方法,遍历,平方, 排序

class Solution(object):
    def sortedSquares(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        return sorted([i**2 for i in A])

还有可以用归并排序,两个指针(bryant)

728. 自除数

自除数 是指可以被它包含的每一位数除尽的数。

例如,128 是一个自除数,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。

还有,自除数不允许包含 0 。

给定上边界和下边界数字,输出一个列表,列表的元素是边界(含边界)内所有的自除数。

  • 示例 1:
    输入:
    上边界left = 1, 下边界right = 22
    输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
    注意:

每个输入参数的边界满足 1 <= left <= right <= 10000。

class Solution(object):
    def selfDividingNumbers(self, left, right):
        """
        :type left: int
        :type right: int
        :rtype: List[int]
        """
        list1 = []
        for num in range(left,right+1): # 遍历区间的每一个数字
            sum1 = 0 # 记录是否每个数都除的尽

            if '0' in str(num): # 跳过包含 0 的项
                continue

            for item in str(num): # 遍历每一个数字的每一位
                if num % int(item) == 0: #自除数
                    sum1+=1

            if sum1 == len(str(num)): #if 每个数都除的尽
                list1.append(num)
        return list1

507. 完美数

对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为“完美数”。

给定一个 整数 n, 如果他是完美数,返回 True,否则返回 False

  • 示例:
    输入: 28
    输出: True
    解释: 28 = 1 + 2 + 4 + 7 + 14

  • 提示:
    输入的数字 n 不会超过 100,000,000. (1e8)

思路:要注意,1不符合条件,不过貌似测试样例会给负数,因为负数的小数次幂得到的是复数,一直报错!我们只用遍历 2到 sqrt(num) 即可

class Solution(object):
    def checkPerfectNumber(self, num):
        """
        :type num: int
        :rtype: bool
        """
        if num <= 1: # 这个限制很关键
            return False
        sum1 = 1
        for i in range(2,int(num**0.5)+1):
            if num % i == 0:
                sum1+= i
                sum1+=num//i

        if num == sum1:
            return True
        else:
            return False

908. 最小差值 I

给定一个整数数组 A,对于每个整数 A[i],我们可以选择任意 x 满足 -K <= x <= K,并将 x 加到 A[i] 中。

在此过程之后,我们得到一些数组 B。

返回 B 的最大值和 B 的最小值之间可能存在的最小差值。

  • 示例 1:
    输入:A = [1], K = 0
    输出:0
    解释:B = [1]

  • 示例 2:
    输入:A = [0,10], K = 2
    输出:6
    解释:B = [2,8]

  • 示例 3:
    输入:A = [1,3,6], K = 3
    输出:0
    解释:B = [3,3,3] 或 B = [4,4,4]

  • 提示:
    1 <= A.length <= 10000
    0 <= A[i] <= 10000
    0 <= K <= 10000

思路:相当于 A 中的每个数字在 [-K,K] 的范围内波动,求波动后 B 中最大元素与最小元素差值的最小值!我们先计算出原来 A 中的差值,然后比较差值与 2K 的大小,如果小于 2K,那么最小差值能被波动抹平,自然是0,如果大于 2K,波动最多只能缩小 2K 的差距,也即 max - K and min+K

class Solution(object):
    def smallestRangeI(self, A, K):
        """
        :type A: List[int]
        :type K: int
        :rtype: int
        """
        A_min = min(A)
        A_max = max(A)
        
        result = A_max - A_min - 2*K
        
        if result > 0:
            return result
        else:
            return 0

剑指 Offer 64. 求1+2+…+n (and)

https://leetcode-cn.com/problems/qiu-12n-lcof

求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

示例 1:

输入: n = 3
输出: 6


难点在于限制条件,我们用 and 关键字 (短路效应及其特性) 来代替 if,用递归调用来代替使用 for 或者 while

逻辑运算符的短路效应:

常见的逻辑运算符有三种,即 “与 && ”,“或 || ”,“非 !” ;而其有重要的短路效应,如下所示:
if(A && B) // 若 A 为 false ,则 B 的判断不会执行(即短路),直接判定 A && B 为 false
if(A || B) // 若 A 为 true ,则 B 的判断不会执行(即短路),直接判定 A || B 为 true

作者:jyd
链接:https://leetcode-cn.com/problems/qiu-12n-lcof/solution/mian-shi-ti-64-qiu-1-2-nluo-ji-fu-duan-lu-qing-xi-/
来源:力扣(LeetCode)

and 只要左边的表达式为真,整个表达式返回的值是右边表达式的值,否则,返回左边表达式的值

class Solution(object):
    def sumNums(self, n):
        """
        :type n: int
        :rtype: int
        """
        # return n*(n+1)/2
        return n and self.sumNums(n-1) + n

以 n = 3 为例

return 3 and f(2)+3
return 2 and f(1)+2
return 1 and f(0)+1
return 0 and f(-1)+0

递归
return 0 and f(-1)+0 => return 0
return 1 and f(0)+1 => return 1 and 0+1 => return 1 and 1 => return 1
return 2 and f(1)+2 => return 2 and 1+2 => return 2 and 3 => return 3
return 3 and f(2)+3 => return 3 and 3+3 => return 3 and 6 => return 6

答案为 6


462. 最少移动次数使数组元素相等 II(中位数)

给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。

  • 例如:
    输入:
    [1,2,3]
    输出:
    2

  • 说明:
    只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1):
    [1,2,3] => [2,2,3] => [2,2,2]

思路,排序后找到中位数,到中位数的移动次数最少(其实我也没有能完全 get,为什么到中位数移动次数最少,最好是能证明一下,哈哈哈)!

class Solution(object):
    def minMoves2(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums = sorted(nums)
        
        l = len(nums)

        if l % 2 == 0:
            mid = (nums[l/2] + nums[(l-1)/2]) // 2
        else:
            mid = nums[l//2]

        sum1 = 0

        for i in nums:
            sum1+= abs(mid-i)
            
        return sum1

还有解题思路是相遇!(bryant)

1. 两数之和(无序用Hash)

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

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

1)暴力法
两层循环嘛

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        for i in range(len(nums)-1):# 0-倒数第二个
            for j in range(i+1,len(nums)): # i的下一个到最后一个
                if nums[i]+ nums[j] == target:
                    return [i,j]

2)Hash 表
思路
建立一个字典,keys 存当前元素达到 target 所需要的数值,values 存的是当前元素的下标!(也就是说第 values 个元素需要找 keys 才能匹配成功!)
遍历数组元素,判断元素是否在字典的 keys 中
如果在,匹配成功,返回元素下标和字典的 values(也即自己另一半在数组中的下标)!
如果不在,新增一个字典 item,将该元素达到 target 所需的数字存为 keys,该元素下标存为 values!参考 [LeetCode]1.TwoSum(Python实现)

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dict1 = {}
        for i,num in enumerate(nums):
            if  nums[i] in dict1:
                return [i,dict1[nums[i]]] 
            else:
                dict1[target-nums[i]] = i

167. 两数之和 II - 输入有序数组(双指针) 有序的话用双指针就可以

75. 颜色分类(荷兰国旗)

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

  • 注意:
    不能使用代码库中的排序函数来解决这道题。

  • 示例:
    输入: [2,0,2,1,1,0]
    输出: [0,0,1,1,2,2]

  • 进阶:
    一个直观的解决方案是使用计数排序的两趟扫描算法。
    首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
    你能想出一个仅使用常数空间的一趟扫描算法吗?


1)桶排序

第一个想法当然是桶排序,参考本博客 347. 前 K 个高频元素 中对桶排序的描述!

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        buckets = [0]*3

        for i in nums:
            buckets[i]+=1
            
        del nums[:] # 哈哈很精髓,注释中说了不要改
        
        for i in range(len(buckets)):
            if buckets[i]:
                nums.extend([i]* buckets[i])

不过题目要求原地算法,所以有瑕疵!

在计算机科学中,一个原地算法(in-place algorithm)是一种使用小的,固定数量的额外之空间来转换资料的算法。当算法执行时,输入的资料通常会被要输出的部份覆盖掉。不是原地算法有时候称为非原地(not-in-place)或不得其所(out-of-place)——百度百科

2)利用快排序的思想

这个问题我们可以将这个问题视为一个数组排序问题,这个数组分为前部,中部和后部(0,1,2)三个部分!

思路如下:将前部和后部各排在数组的前边和后边,中部自然就排好了。具体的:

设置两个标志位 begin 和 end 分别指向这个数组的开始和末尾,然后用一个标志位 current 从头开始进行遍历:

  • 若遍历到的位置为 0,则说明它一定属于前部,于是就和 begin 位置进行交换,然后 current 向前进,begin 也向前进(表示前边的已经都排好了)。
  • 若遍历到的位置为 1,则说明它一定属于中部,根据总思路,中部的我们都不动,然后 current 向前进。
  • 若遍历到的位置为 2,则说明它一定属于后部,于是就和 end 位置进行交换,由于交换完毕后 current 指向的可能是属于前部的,若此时 current 前进则会导致该位置不能被交换到前部,所以此时 current 不前进),end 向后退1。

参考

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        start = 0
        end = len(nums)-1
        current = 0

        while current<=end:
            if nums[current]==2: # 这里没有 current++ 小心这个坑
                nums[current],nums[end] = nums[end], nums[current]
                end-=1
            elif nums[current]==0:
                nums[current],nums[start] = nums[start], nums[current]
                current+=1
                start+=1
            else:
                current+=1

999. 车的可用捕获量(上下左右遍历)

在一个 8 x 8 的棋盘上,有一个白色车(rook)。也可能有空方块,白色的象(bishop)和黑色的卒(pawn)。它们分别以字符 “R”,“.”,“B” 和 “p” 给出。大写字符表示白棋,小写字符表示黑棋。

车按国际象棋中的规则移动:它选择四个基本方向中的一个(北,东,西和南),然后朝那个方向移动,直到它选择停止、到达棋盘的边缘或移动到同一方格来捕获该方格上颜色相反的卒。另外,车不能与其他友方(白色)象进入同一个方格。

返回车能够在一次移动中捕获到的卒的数量。
在这里插入图片描述
在这里插入图片描述
思路:定位到车的位置,然后以车为原点,上下左右四条路出发,if 遇到象就直接break,else 遇到兵,结果+1,也 break(注意:因为不可能是肉弹战车,横扫千军)

class Solution(object):
    def numRookCaptures(self, board):
        """
        :type board: List[List[str]]
        :rtype: int
        """
        # 定位
        flag = False
        for row in range(len(board)):
            for col in range(len(board[0])):
                if board[row][col] == "R":
                    flag = True
                    break
            if flag == True:
                break
                
        count = 0
		# 上
        for i in reversed(range(row)):
            if board[i][col] == "B":
                break
            elif board[i][col] == "p":
                count+=1
                break
		# 下
        for i in range(row+1,len(board[0])):
            if board[i][col] == "B":
                break
            elif board[i][col] == "p":
                count+=1   
                break
		# 左
        for j in reversed(range(col)):
            if board[row][j] == "B":
                break
            elif board[row][j] == "p":
                count+=1
                break
		# 右
        for j in range(col+1,len(board)):
            if board[row][j] == "B":
                break
            elif board[row][j] == "p":
                count+=1  
                break
        return count

766. 托普利茨矩阵(比较两行)

如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵。

给定一个 M x N 的矩阵,当且仅当它是托普利茨矩阵时返回 True。

示例 1:

输入:
matrix = [
[1,2,3,4],
[5,1,2,3],
[9,5,1,2]
]
输出: True
解释:
在上述矩阵中, 其对角线为:
“[9]”, “[5, 5]”, “[1, 1, 1]”, “[2, 2, 2]”, “[3, 3]”, “[4]”。
各条对角线上的所有元素均相同, 因此答案是True。
示例 2:

输入:
matrix = [
[1,2],
[2,2]
]
输出: False
解释:
对角线"[1, 2]"上的元素不同。

思路:这个题一开始准备找对角线的规律,但是发现很难找,再仔细想想,每行的第一个到倒数第二个应该和下一行的第二个到最后一个相等,才能满足条件!这样的话,问题就容易了很多!

class Solution(object):
    def isToeplitzMatrix(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: bool
        """
        m = len(matrix)
        n = len(matrix[0])
        for i in range(m-1):
            if matrix[i][:-1] != matrix[i+1][1:]:
                return False
        return True

1103. 分糖果 II

排排坐,分糖果。

我们买了一些糖果 candies,打算把它们分给排好队的 n = num_people 个小朋友。

给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友 n 颗糖果。

然后,我们再回到队伍的起点,给第一个小朋友 n + 1 颗糖果,第二个小朋友 n + 2 颗,依此类推,直到给最后一个小朋友 2 * n 颗糖果。

重复上述过程(每次都比上一次多给出一颗糖果,当到达队伍终点后再次从队伍起点开始),直到我们分完所有的糖果。注意,就算我们手中的剩下糖果数不够(不比前一次发出的糖果多),这些糖果也会全部发给当前的小朋友。

返回一个长度为 num_people、元素之和为 candies 的数组,以表示糖果的最终分发情况(即 ans[i] 表示第 i 个小朋友分到的糖果数)。

  • 示例 1:
    输入:candies = 7, num_people = 4
    输出:[1,2,3,1]

  • 示例 2:
    输入:candies = 10, num_people = 3
    输出:[5,2,3]

思路:位置+1,糖果数+1,位置要对总人数取余数达到循环的效果!取剩余糖果数和当前位置该发的糖果数的最小值来发糖果!

class Solution(object):
    def distributeCandies(self, candies, num_people):
        """
        :type candies: int
        :type num_people: int
        :rtype: List[int]
        """
        result = [0]*num_people
        position = 0 # 给该位置学生发糖果
        candy = 1 # 发糖果的数量

        while(candies>0): # 当剩余糖果大于0
            result[position] += min(candy,candies) # 取 应该发的,和剩有的糖果的最小值
            candies -= candy # 糖果总数减去发的糖果
            position+=1 # 下一位同学
            position = position % num_people # 取余
            candy+=1 # 该发的糖果数+1
        return result

1030. 距离顺序排列矩阵单元格

给出 R 行 C 列的矩阵,其中的单元格的整数坐标为 (r, c),满足 0 <= r < R 且 0 <= c < C。

另外,我们在该矩阵中给出了一个坐标为 (r0, c0) 的单元格。

返回矩阵中的所有单元格的坐标,并按到 (r0, c0) 的距离从最小到最大的顺序排,其中,两单元格(r1, c1) 和 (r2, c2) 之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|。(你可以按任何满足此条件的顺序返回答案。)

  • 示例 1:
    输入:R = 1, C = 2, r0 = 0, c0 = 0
    输出:[[0,0],[0,1]]
    解释:从 (r0, c0) 到其他单元格的距离为:[0,1]

思路:遍历矩阵,用二维数组存放坐标和距离,行是距离,列是对应的坐标,因为存在一个距离对应多个坐标的情况,然后遍历二维数组,依次取出坐标

class Solution(object):
    def allCellsDistOrder(self, R, C, r0, c0):
        """
        :type R: int
        :type C: int
        :type r0: int
        :type c0: int
        :rtype: List[List[int]]
        """
        list1 = [[] for i in range(200)] # 这里创建的数组需要是二维,行值,列坐标,存在一值多坐标,所以要初始化为二维

        for i in range(R):
            for j in range(C):
                list1[abs(i-r0)+ abs(j-c0)].append([i,j])  # 根据题意来填补值和坐标

        result = []  
        for i in list1: # 遍历列表
            if i:
                result.extend(i) # 因为存在一值多坐标的情况,所以不是 append,而是 extend
        return result

283. 移动零

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

  • 示例:
    输入: [0,1,0,3,12]
    输出: [1,3,12,0,0]

思路:第一个非零的数移动到第一个位置,原来的位置置为0,第二个非零的数移动到第二个位置,原来的位置置为0,需要注意的是,如果没有发生移动的情况,就不应该有置零的操作,不然那个数字就消失了,我通过 count 计数来实现这个不移动的情况!

class Solution(object):
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        count = 0
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[count] = nums[i]
                if i != count: # 第i(下标0)个位置,有i个非零的数,就不能置零了
                    nums[i] = 0
                count+=1 # 统计非零的次数
        return nums

1185. 一周中的第几天

给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。

输入为三个整数:day、month 和 year,分别表示日、月、年。

您返回的结果必须是这几个值中的一个 {“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”}。

  • 示例 1:
    输入:day = 31, month = 8, year = 2019
    输出:“Saturday”

思路:1年1月1日是星期一,统计离1年1月1日过了多少天,模 7,计算星期几

class Solution(object):
    def dayOfTheWeek(self, day, month, year):
        """
        :type day: int
        :type month: int
        :type year: int
        :rtype: str
        """
        # month = 3, 统计 1,2月份日期之和
        # 非闰年,365 天
        month_no = {
            1:0,
            2:31,
            3:31+28,
            4:31+28+31,
            5:31+28+31+30,
            6:31+28+31+30+31,
            7:31+28+31+30+31+30,
            8:31+28+31+30+31+30+31,
            9:31+28+31+30+31+30+31+31,
            10:31+28+31+30+31+30+31+31+30,
            11:31+28+31+30+31+30+31+31+30+31,
            12:31+28+31+30+31+30+31+31+30+31+30}

        # month = 3, 统计 1,2月份日期之和
        # 闰年,366 天
        month_leap = {
            1:0,
            2:31,
            3:31+29,
            4:31+29+31,
            5:31+29+31+30,
            6:31+29+31+30+31,
            7:31+29+31+30+31+30,
            8:31+29+31+30+31+30+31,
            9:31+29+31+30+31+30+31+31,
            10:31+29+31+30+31+30+31+31+30,
            11:31+29+31+30+31+30+31+31+30+31,
            12:31+29+31+30+31+30+31+31+30+31+30}

        everyday = {
            0:"Sunday", 
            1:"Monday", 
            2:"Tuesday", 
            3:"Wednesday", 
            4:"Thursday", 
            5:"Friday", 
            6:"Saturday"}

        total_days = 0
		# 处理年,平年365,闰年366
        for i in range(1,year):
            if (i % 4 == 0 and i % 100 != 0) or (i % 400 == 0): # 如果是闰年
                total_days += 366
            else:
                total_days += 365
		# 处理月和天,区别平闰年
        if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0): # 如果是闰年
            total_days += (month_leap[month] + day)
        else:
            total_days += (month_no[month] + day)
		# 模 7 取结果
        result = everyday[(total_days)%7]
        return result

1299. 将每个元素替换为右侧最大元素

给你一个数组 arr ,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1 替换。

完成所有替换操作后,请你返回这个数组。

示例:

输入:arr = [17,18,5,4,6,1]
输出:[18,6,6,6,1,-1]

提示:

1 <= arr.length <= 10^4
1 <= arr[i] <= 10^5


暴力法

result = arr[:]
for i in range(len(arr)-1):
    result[i] = max(arr[i+1:])
result[-1] = -1
return result

逆序法

思路:逆序只用遍历一次

以 [17,18,5,4,6,1] 为例

1 位置上的最终结果为 -1

6 位置上的最终结果应该是 6 位置后一位的最终结果与 6 位置的 后一位对应值的最大值,也即 max(-1,1) = 1

4 位置上的最终结果应该是 4 位置后一位的最终结果与 4 位置的 后一位对应值的最大值,也即 max(1,6) = 6

5 位置上的最终结果应该是 5 位置后一位的最终结果与 5 位置的 后一位对应值的最大值,也即 max(6,4) = 6

18 位置上的最终结果应该是 18 位置后一位的最终结果与 18 位置的 后一位对应值的最大值,也即 max(6,5) = 6

17 位置上的最终结果应该是 17 位置后一位的最终结果与 17 位置的 后一位对应值的最大值,也即 max(6,18) = 18

n = [0]*(len(arr)-1) + [-1]

for i in range(len(arr)-2, -1, -1):
    n[i] = max(n[i+1], arr[i+1])
return n

976. 三角形的最大周长

给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。

如果不能形成任何面积不为零的三角形,返回 0。

示例 1:

输入:[2,1,2]
输出:5
示例 2:

输入:[1,2,1]
输出:0
示例 3:

输入:[3,2,3,4]
输出:10
示例 4:

输入:[3,6,2,3]
输出:8

暴力法肯定超时

class Solution(object):
    def largestPerimeter(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        res = 0
        A = sorted(A)
        for i in range(len(A)-2):
            for j in range(i+1,len(A)-1):
                for k in range(j+1,len(A)):
                    if A[i]+A[j]>A[k] and A[i]+A[j]+A[k]>res:
                        res = A[i]+A[j]+A[k]
        return res

一个比较好的思路是,取当前长度最长的三条边,他们能组成三角形的话,周长肯定是最大的,如果组成不了,说明,第三长的边+第二长的边<最长的边,换句话说就是,数组里剩下的边与最长的边也可能组成三角形了,也即最长的边应该抛弃掉!

从余下的数组中选出最大的三条边,周而复始……

class Solution(object):
    def largestPerimeter(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        res = 0
        A = sorted(A,reverse=True)
        
        for i in range(len(A)-2):
            if A[i+1] + A[i+2] > A[i]:
                return A[i+1] + A[i+2] + A[i]
        return 0

;