leetcode 每天10道travl

1、找到 a,找到 b,让 a + b = target

思路:将{a:b}={a:target-a} 的形式不断探寻字典

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


if __name__ == "__main__":
    nums = [2, 7, 11, 15]
    target = 9
    assert (Solution().twoSum(nums, target) == [0, 1])
   # print(Solution().twoSum(nums, target))
   #  nums = [3, 2, 4]
   #  target = 6
   #  assert (Solution().twoSum(nums, target) == [1, 2])

 

2、两个长整数之和

思路:利用链表对整数个从位到最高位依次相加

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None


class Solution:
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        head = ListNode(0)
        p = head
        quot = 0
        while l1 or l2 or quot != 0:
            if l1:
                quot += l1.val
                l1 = l1.next
            if l2:
                quot += l2.val
                l2 = l2.next
            quot, rem = divmod(quot, 10)   #return the tuple (x//y, x%y)
            print(quot,rem)
            p.next = ListNode(rem)
            p = p.next

        return head.next


def compareLinkedList(l1, l2):
    while l1 or l2:
        if not (l1 and l2) or l1.val != l2.val:
            return False
        l1 = l1.next
        l2 = l2.next
    return True


if __name__ == "__main__":
    l1 = ListNode(2)
    l1.next = ListNode(4)
    l1.next.next = ListNode(3)
    l2 = ListNode(5)
    l2.next = ListNode(6)
    l2.next.next = ListNode(4)
    lsum = ListNode(7)
    lsum.next = ListNode(0)
    lsum.next.next = ListNode(8)
    print(compareLinkedList(Solution().addTwoNumbers(l1, l2), lsum))

3、相同数=树

思路:递归还是那个递归,门口有一颗二叉树,另一颗也是二叉树。它们长得一样不?从根开始看呗

class Tree:
    def __init__(self,x):
        self.val=x
        self.left=None
        self.right=None

class Solution:
    def is_same(self,p,q):
        if p and q:
            return p.val==q.val and self.is_same(p.left,q.left) and self.is_same(p.right,q.right)
        return p is q


if __name__ == '__main__':
    example=Tree(1)
    example.left=Tree(2)
    example.right=Tree(3)
    assert (Solution().is_same(example,example) is True)

 

4、没有重复字符的最长子字符串的长度

思路:

class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        tmp = 0
        p = 0
        dic = {}
        for index, value in enumerate(s):
            if value in dic and dic[value] >= p:
                tmp = max(tmp, index - p)   #tmp记录当前最长字符串,index - p 指代上一个没有重复的子字符串长度
                p = dic[value] + 1           
            dic[value] = index
        return max(tmp, len(s) - p)   #针对‘abc’的情况跟


if __name__ == "__main__":
    print(Solution().lengthOfLongestSubstring("abcabcbb") == 3)
    print(Solution().lengthOfLongestSubstring("abba") == 2)
    print(Solution().lengthOfLongestSubstring("pwwkew") == 3)

 

5、给一组数据,返回两组边界中可盛放水最多的一组

Input: [1,8,6,2,5,4,8,3,7]
 Output: 49

 

上面的垂直线由数组[1,8,6,2,5,4,8,3,7]表示。在这种情况下,容器可容纳的最大水面积(蓝色部分)为49。

思路:有两个指针从两端开始走,若它们相加大于目标,那么就把右边的指针向前挪一位,反之左边的挪一位
 

def size(nums):
    l,r=0,len(nums)-1
    tmp=0

    while l<r:
        tmp=max(tmp,min(nums[r],nums[l])*(l-r))
        if nums[r]<nums[l]:
            r-=1
        else:
            l+=1

    return tmp

6、交换糖果

Alice和Bob有不同大小的糖果棒:A [i]是Alice拥有的第i个糖果棒的大小,B [j]是Bob拥有的第j个糖果棒的大小。

由于他们是朋友,他们想交换一个糖果,以便交换后,他们都有相同的糖果总量。(一个人拥有的糖果总量是他们拥有的糖果大小的总和。)

返回一个整数数组ans,其中ans [0]是Alice必须交换的糖的大小,ans [1]是Bob必须交换的糖的大小。

输入:A = [1,1],B = [2,2]

    产出:[1,2]

 

 有两个好盆友,要交换糖果使得他们两个的糖果一样。
输出的结果也是交换的糖果数量而不是下标,所以非常容易写。
设爱丽丝给 x 颗糖,得到 y颗。那鲍勃就给 y 得到 x。
最终是 
1? - x + y = 2? - y + x
2x - 2y = 1? - 2?
x - y = (1? - 2?) / 2    #其中x-y代表糖的增量

def tang(A,B):
    tmp=(sum(A)-sum(B))//2
    for  i in A:
        if i-tmp in B:
            return (i,i-tmp)     #代表糖的增量值恰好可以被两个数组中元素满足

 

 

二、回溯 (本质,通过递归从结果推断原因)

给定n对括号,编写一个函数来生成格式正确的括号的所有组合。

For example, given n = 3, a solution set is:
[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

class Solution(object):
    def generatetmp(self, n):
        """
        :tlabel2pe n: int
        :rtlabel2pe: List[str]
        """
        result = []
        
        def kuo(label1, label2, tmp):  #这里label 代表 '('的数量 ,label2代表 ')'的数量
            if not label1 and not label2:
                result.append(tmp)
                return
            
            if label2 > label1:
                kuo(label1, label2-1, tmp=tmp+')')
            
            if label1:  #代表,每次循环都有可能加入"('  代表搜索空间,且设置label1为条件,由于label1在条件语句中是递减的!
                #print('tmp',tmp)
                kuo(label1-1, label2, tmp=tmp+'(')
        
        kuo(n-1, n, '(')
        
        return result
a=Solution().generatetmp(3)
print(a)

7、给定按升序排序的整数数组,找到给定目标值的起始位置和结束位置。
算法的运行时复杂度必须为O(log n)。
如果在数组中找不到目标,则返回[-1,-1]。
例1:
输入:nums = [5,7,7,8,8,10],目标= 8
产出:[3,4]
例2:
输入:nums = [5,7,7,8,8,10],目标= 6
输出:[-1,-1]

思路:改良二分法,由于要找的是两个数,因此要判断,找到target时,移动左边还是右边

class Solution(object):
    def find_right(self,nums,target):
        l,r=0,len(nums)
        res=[]
        while l<r:
            mid=l+(r-l)//2
            if nums[mid]==target:
                res.append(mid)
            if nums[mid]>target:
                r=mid
            else:                        # 用【1,2,2,2,6】为例子,相等时,移动左边指针,判断mid右边是否还有target,有的话加入列表,最后列表返回最后一个元素
                l=mid+1
        print('right',res)
        return res[-1] if res else -1

    def find_left(self,nums,target):
        l,r=0,len(nums)
        res=[]
        while l<r:
            mid=l+(r-l)//2
            if nums[mid]==target:
                res.append(mid)
            if nums[mid]<target:
                l=mid+1
            else:                  # 用【1,2,2,2,6】为例子,相等时,移动右边指针
                r=mid
        print('left',res)
        return res[-1] if res else -1

    def find_target(self,nums,target):
        left=self.find_left(nums,target)
        print('11111111111')
        if left==-1:
            return [-1,-1]
        return [left,self.find_right(nums,target)]



a=[5,7,7,8,8,10]
b=Solution().find_target(a,8)
print(b)

 

 

 

8、假设按升序排序的数组在事先未知的某个枢轴处旋转。
(即[0,1,2,4,5,6,7]可能变为[4,5,6,7,0,1,2])。
找到最小元素。
您可以假设数组中不存在重复。
例1:
输入:[3,4,5,1,2] 
输出:1
例2:
输入:[4,5,6,7,0,1,2]
输出:0

思路:找到旋转点,旋转点即比列表中第一个元素更小的数 ,二分法目标为首元素

class Solution:
    def find_rotate(self,nums):

        l = 1
        r = len(nums)
        count=0
        target=nums[0]

        while l <r:
            count+=1
            mid =l+(r-l) // 2
            if nums[mid] > target:    #此处重点,和二分法不同
                l =mid+1
            else:
                r =mid
        return nums[l]


    def find_min(self,nums):
        index=self.find_rotate(nums)

        if index>=len(nums):
            return nums[0]
        return nums[index]

a=Solution().find_rotate([5,6,7,8,9,10,2,3])
print(a)

 

思路:峰值应比较相邻的值,二分法目标为相邻值

def find_max(nums):
    l,r=0,len(nums)
    #target=nums[0]
    while l<r:
        mid=l+(r-l)//2
        if nums[mid]<nums[mid+1]:
            l=mid+1
        else:
            r=mid
    return nums[l]

a=[6,10,8,7]
b=find_max(a)
print(b)

 

9、Find the minimum element.

Input: [2,2,2,0,1]
Output: 0

class Solution:
    def find_rotate(self,nums):
        tmp=nums[0]
        index=0
        for i in nums:
            if i==tmp:
                index+=1

        lp=index
        rp=len(nums)
        while lp<rp:
            mid=lp+(rp-lp)//2
            if nums[mid]>tmp:
                lp=mid+1
            else:
                rp=mid
        return lp

    def find_min(self,nums):
        a=self.find_rotate(nums)
        if a==len(nums):
            return nums[0]
        return nums[a]


if __name__ == '__main__':
    a=Solution().find_min([2,3,4,5,6,1])
    print(a)

 

10、球场C 可容纳 M*N个球迷。统计有几组球迷群体:
1. 每组球迷群体会选择相邻的作为(8个方位。)
2. 不同球迷群体不会相邻。
3. 给一个 M*N 的二维球场,0为没人,1为有人,求出群体个数P以及最大的群体人数Q.

 

test = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
]

# 6 8

def makeAroundXY(x, y):
    # ((x, y)....)
    return ((x, y-1),
            (x, y+1),
            (x-1, y),
            (x+1, y),
            (x-1, y-1),
            (x-1, y+1),
            (x+1, y+1),
            (x+1, y-1))

def getFootballFans(nums):
    """
        [[0, 0, 0].....]
        从 0,0 开始,如果遇到1则进入递归:
        递归结束条件:
            四周都是 0或边界。
            结束时将搜索到的人数添加。
        未结束时根据四周的情况进入相同的递归。
    """

    fans_groups = []
    x = 0
    y = 0

    y_label = len(nums[0])
    x_label = len(nums)

    def fans(x, y, count=0):
      #  nonlocal nums
        Xy = makeAroundXY(x, y)
        for i in Xy:
            try:
                if i[0] < 0 or i[1] < 0:   #边界
                    continue

                if nums[i[0]][i[1]] == 1:
                    nums[i[0]][i[1]] = 0
                    count += 1
                    t = fans(i[0], i[1], 0)
                    count += t
            except IndexError:
                continue
        return count


    for x in range(x_label):
        for y in range(y_label):
            if nums[x][y] == 1:
                nums[x][y] = 0
                fans_groups.append(fans(x, y, 1))



    if not fans_groups:
        return (0, 0)

    return (len(fans_groups), max(fans_groups))

a=getFootballFans(test)
print(a)

 

11、给定二叉树,找到树的最后一行中最左边的值。
例1:
输入:
    2
   / \
  1 3
输出:    1
例2: 
输入:
        1
       / \
      2 3
     / / \
    4 5 6
       /
      7

输出:    7

思想: 广度优先,从右向左,弹出最后一个

 

class Solution(object):
    def findBottomLeftValue(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        queue = [root]
        res = []          #之所以指定新列表是由于,queue列表会弹出一个数的同时添加两个数,造成死循环
        result = root.val
        
        while 1:
            while queue:     
                node = queue.pop()
                if node.right:
                    res.append(node.right)
                    result = node.right.val
                if node.left:
                    res.append(node.left)
                    result = node.left.val
            if not res:
                return result
            queue.extend(res[::-1])   #列表添加列表的方法,变为【left,right】 pop()先弹出right
            res = []

12、分水果

在一排树中,第i棵树产生具有树型[i]的果实。
从任意树开始,然后重复执行以下步骤:
1.将这棵树上的一片水果加到你的篮子里。如果你不能,停下来。
2.移动到当前树右侧的下一个树。如果右边没有树,请停止。
请注意,在初始选择起始树后,您没有任何选择:您必须执行步骤1,然后执行步骤2,然后返回步骤1,然后执行步骤2,依此类推,直至停止。
你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子每个只携带一种水果。
您可以使用此程序收集的水果总量是多少?
 
例1:
输入:[1,2,1]
输出:3
说明:我们可以收集[1,2,1]。
例2:
输入:[0,1,2,2]
输出:3
说明:我们可以收集[1,2,2]。
如果我们从第一棵树开始,我们只会收集[0,1]。
例3:
输入:[1,2,3,2,2]
产量:4
说明:我们可以收集[2,3,2,2]。
如果我们从第一棵树开始,我们只会收集[1,2]。
例4:
输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
说明:我们可以收集[1,2,1,1,2]。
如果我们从第一棵树或第八棵树开始,我们只会收集4个水果。
对于每一个i,都会产生tree [i]类型的水果。有两个篮子,每个篮子只能放一种类型,但同类型的不限次数。
问最多能摘的水果数量。

转换数学思想 : 从一个列表中选取连续重复子列表最大长度(子列表为2个数字重复)

class Solution:
    # def tongji(self,res,i):    #自己写个计数器
    #     if i not in res:
    #         res[i]=1
    #     else:
    #         res[i]+=1
    #     return res
 
    def totalFruit(self, nums):
        dic={}
        count, res = 0, 0
        print(dic)
        for i in range(len(nums)):
            dic[nums[i]]=dic[nums[i]]+1 if nums[i] in dic else 1
            print(dic)
            while len(dic) > 2:
                dic[nums[count]] -= 1 
                if not dic[nums[count]]:
                    dic.pop(nums[count])
                count += 1             #count统计字典中第一个元素出现次数
                # print('dic_last',dic)
                # print('l',count)
                # print('nums[l]',nums[count])
            res = max(res, i - count + 1)  #  i-count 总元素出现次数-第一个元素出现次数 , 由于i从0开始所以+1
        return res
 
a=Solution().totalFruit([0,1,2,2])
print(a)

 

12、三元递增

如果存在i,j,k则返回true 
这样arr [i] <arr [j] <arr [k]给定0≤i<j <k≤n-1否则返回false。
注意:您的算法应该以O(n)时间复杂度和O(1)空间复杂度运行。
例1:
输入:[1,2,3,4,5]
输出:true
例2:
输入:[5,4,3,2,1]
输出:false
给一个数组,若里面存在arr [i] <arr [j] <arr [k]且0 <= i <j <k <= n-1,则返回True。
否则假。

nums=[5,4,3,2,1]


def ok(nums):
    once=False
    tmp=nums[0]
    for i in range(1,len(nums)):
        if once ==False and tmp<nums[i]:
            once=True
            tmp=nums[i]
            continue
        if once==True and tmp<nums[i]:
            return True

    return False

print(ok(nums))

 

12、最大岛屿面积
给定0和1的非空二维阵列网格,岛是一组1(表示陆地)4方向连接(水平或垂直)。您可以假设网格的所有四个边缘都被水包围。
找到给定2D阵列中岛的最大面积。(如果没有岛,则最大面积为0.)
例1:
[[0,0,1,0,0,0,0,1,0,0,0,0,0]
 [0,0,0,0,0,0,0,1,1,1,0,0,0]
 [0,1,1,0,1,0,0,0,0,0,0,0,0]
 [0,1,0,0,1,1,0,0,1,0,1,0,0]
 [0,1,0,0,1,1,0,0,1,1,1,0,0]
 [0,0,0,0,0,0,0,0,0,0,1,0,0]
 [0,0,0,0,0,0,0,1,1,1,0,0,0]
 [0,0,0,0,0,0,0,1,1,0,0,0,0]]
给出上面的网格,返回6.注意答案不是11,因为岛必须是4向连接。
例2:
[[0,0,0,0,0,0,0,0]]
给定上面的网格,返回0。
注意:给定网格中每个维度的长度不超过50。

class Solution():
    def find4(self,x,y):
        return ((x+1,y),
                (x-1,y),
                (x,y+1),
                (x,y-1))

    def find_max(self,nums):
        y_label=len(nums[0])
        x_label=len(nums)
        res=[]

        def find_point(x,y,count=0):
            maybe=self.find4(x,y)
            for tmp in maybe:
                try:
                    if tmp[0]<0 or tmp[1]<0:
                        continue
                    if nums[tmp[0]][tmp[1]]==1:
                        nums[tmp[0]][tmp[1]]=0
                        count+=1
                        t=find_point(tmp[0],tmp[1],count=0)
                        count+=t
                except IndexError:
                    break
            return count

        for i in range(x_label):
            for j in range(y_label):
                if nums[i][j]==1:
                    nums[i][j]=0
                    res.append(find_point(i,j,count=1))
                    
        

        return max(res)


test = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
]
s=Solution().find_max(test)
print(s)



13、插入间隔
给定一组非重叠间隔,在间隔中插入新间隔(必要时合并)。
您可以假设间隔最初是根据其开始时间排序的。
例1:
输入:interval = [[1,3],[6,9]],newInterval = [2,5]
产出:[[1,5],[6,9]]
例2:
输入:interval = [[1,2],[3,5],[6,7],[8,10],[12,16]],newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
说明:因为新区间[4,8]与[3,5],[6,7],[8,10]重叠。

 

class Solution(object):
    def insert(self, nums, new_nums):
        """
        :type intervals: List[Interval]
        :type new_nums: Interval
        :rtype: List[Interval]
        """
        nums.append(new_nums)
        
        nums = sorted(nums, key=lambda x: x[0])

        if not nums:
            return []

        result = []

        head = nums[0][0]
        tail = nums[0][1]
        for x in range(1, len(nums)):
            i = nums[x]
            if tail >= i[0]:         
                tail = max(tail, i[1])
            else: 
                result.append([head, tail])     #若区间不相交,则加入
                head = i[0]
                tail = i[1]

        result.append([head, tail])
        return result


a=Solution().insert([[1,2],[3,5],[6,7],[8,10],[12,16]],[4, 8])
print(a)

 

14、能组合成最大数

给定一个非负整数列表,将它们排列成最大数字。
例1:
输入:[10,2]
输出:“210”
例2:
输入:[3,30,34,5,9]
输出:“9534330”
注意:结果可能非常大,因此您需要返回一个字符串而不是整数。

class Solution(object):
    def largestNumber(self, nums):
        if not any(nums):

            return '0'
        print(any(nums))

        max_nums = len(str(max(nums)))
        def makeEqual(s, length=max_nums):

            if len(s) == length:
                return s

            s=int(s)
            while length-1>0:
                length-=1
                s+=s*10
            return str(s)

            # 这种补位会通过测试,但是 Leetcode 的测试并没有包含所有的情况。
            # x = max(s) * (length - len(s))   #将[3,5,9] 补位为33,55,99
            # print(s+x)
            # return s+x
        return ''.join(sorted(map(str, nums), key=makeEqual, reverse=True))   #map(str, nums)每个int型str化

a=Solution().largestNumber([3,30,34,5,9])
print(a)

 

14、最长连续子序列

Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.

class Solution:
    def max_length(self,nums):
        count=0

        nums_set=set(nums)

        for i in nums:
            if i-1 not in nums_set:     #使得该值一定是某个连续数字的最小数
                tmp=1
                x=i
                while True:
                    if x+1 in nums_set:
                        tmp+=1
                        x+=1
                    else:
                        count=max(count,tmp)  #用tmp统计子域,count统计全部域
                        break
        return count
a=Solution().max_length([1,2,3,4,100])
print(a)


15、最大连续子数组之积

给定整数数组nums,找到具有最大乘积的数组(包含至少一个数字)内的连续子数组。
例1:
输入:[2,3,-2,4]
产量:6
说明:[2,3]具有最大的产品6。
例2:
输入:[ -  2,0,-1]
输出:0
说明:结果不能为2,因为[-2,-1]不是子数组。

思路:由于是乘法(存在负数)计算,因此最大,最小值之间是可以相互置换的。因此,要同事保存每次的最大,最小值,方便下次计算

绝对值最大的数,不是最大就是最小

class Solution:
    def find_max(self,nums):
        max_value=nums[0]       #假设初始值最大
        last_max_min=[[max_value]]   #用来记录每一次的最大最小值

        for i in range(1,len(nums)):
            max_min=[nums[i]*j for j in last_max_min[-1]] #用当前最大,最小值与每个元素相乘 得到当前最大,最小值

            tmp_max=max(nums[i],max(max_min))       #当前最大最小值与当前值比较
            tmp_min=min(nums[i],min(max_min))
            last_max_min.append([tmp_max,tmp_min])

            max_value=max(max_value,tmp_max)         #记录历史最大值
        return max_value





a=Solution().find_max([2,3,-2,4])
print(a)

17、最大连续子数组之和

“””
给定整数数组nums,找到具有最大总和并返回其总和的连续子数组(包含至少一个数字)。
例:
输入:[ -  2,1,-3,4,-1,2,1,-5,4],
产量:6
说明:[4,-1,2,1]具有最大的和= 6。

 

class Solution:
    def find_max(self,nums):
        tmp=nums[0]       #假设初始值最大
        max_value=nums[0]


        for i in nums[1:]:
            tmp=max(i,i+tmp)              #当前时刻与历史总时刻比较
            print(tmp)
            max_value=max(max_value,tmp)   #max_value记录上一次最大值

        return max_value


a=Solution().find_max([2,3,-2,4])
print(a)


18、给定n个整数的数组,其中n> 1,返回一个数组输出,使得output [i]等于除nums [i]之外的所有nums元素的乘积。
例:
输入:[1,2,3,4]
产量:[24,12,8,6]
注意:请在没有除法的情况下解决,并在O(n)中解决。

思路:

A[0]=1,A[1]=2,A[2]=2*3=6,A[3]=2*3*4=24;
B[0]=3*4*5=60,B[1]=4*5=20,B[2]=5,B[3]=1;
result[0]=A[0]*B[0],result[1]=A[1]*B[1];

 

class Solution(object):
    def productExceptSelf(self, nums):
        
        left = [1]
        right = [1]


        for i in range(len(nums)-1):
            left.append(left[-1] * nums[i])  #[1,2,2*3,2*3*4]

        for i in range(len(nums)-1, 0, -1):
            right.append(right[-1] * nums[i])  #[1,5,20,60]

        length = len(left)

        return  [left[i] * right[length-1-i] for i in range(length)]    # [1*24,1*12,2*4,1*6]
    

 

19、链表删除尾部第n个节点

1->2->3->4->5, and n = 2.

1->2->3->5.

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        q = p = head
        for i in range(n):
            q = q.next
        
        if not q:
            return head.next
        
        while q.next:
            q = q.next
            p = p.next
        
        p.next = p.next.next
        
        return head

20、从旋转过的排序数组中搜索某数

一个被旋转的数组,例如[0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

思路: 先找到旋转点,后判断目标所处的区域,然后用二分搜索

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

    def bi_serch(self,nums,target,l,r):
        while l<r:
            mid=l+(r-l)//2
            if nums[mid]==target:
                return mid
            if nums[mid]<target:
                l=mid+1
            else:
                r=mid
        return -1

    def serarch(self,nums,target):
        if target==nums[0]:
            return 0
        if target<nums[0]:
            l=self.find_rotate(nums)
            r=len(nums)
        else:
            l=0
            r=self.find_rotate(nums)
        return self.bi_serch(nums,target,l,r)


nums = [4,5,6,7,0,1,2]
target = 1
b=Solution().serarch(nums,target)
print(b)

 

21、落单的数
给定一个非空的整数数组,除了一个元素外,每个元素都会出现两次。找一个单一的。
输入:[2,2,1]
输出:1
例2:
输入:[4,1,2,1,2]
产量:4

线性时间内,且不用额外空间。

思路:利用‘与’运算

class Solution(object):
    def find_one(self,nums):
        tmp=nums[0]
        for i in nums[1:]:
            tmp^=i
        return tmp


nums = [4,4,5,5,2,3,3]
target = 1
b=Solution().find_one(nums)
print(b)

21、给定一个非负整数数组A,返回一个由A的所有偶数元素组成的数组,后跟A的所有奇数元素。

输入:[3,1,2,4]
产出:[2,4,3,1]
产出[4,2,3,1],[2,4,1,3]和[4,2,1,3]也将被接受

思路:空列表,偶数加前面,奇数加后面

class Solution(object):
    def even_odd(self,nums):
        res=[]
        for i in nums:
            if i%2==0:
                res=[i]+res
            else:
                res=res+[i]
        return res

nums = [4,4,5,5,2,3,3]
b=Solution().even_odd(nums)
print(b)

22、列表所有子列表的最小值和

给定一个整数数组A,找到min(B)的总和,其中B的范围超过A的每个(连续)子数组。
由于答案可能很大,因此返回模10 ^ 9 + 7的答案。
 
例1:
输入:[3,1,2,4]
产量:17
说明:子阵列是[3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2] ,4],[3,1,2,4]。 
最小值为3,1,2,4,1,1,2,1,1,1。总和为17。

思路:  统计当前数为最小数的列表长度。

对于A中的每一个值A[i],寻找以它为最小值的子序列的数量。也就是说,我们需要寻找A[i]左侧第一个比它大的值的位置,以及右侧第一个比它大的值的位置。然后就可以计算对应的子序列的数量了。

class Solution(object):
 
    def sumSubarrayMins(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        mod = 10**9 + 7
        
        # count
        left = []
        right = []
 
        # (num, count)
        tmp_left = []
        tmp_right = []
        for i in A:                      #统计当前数为最小值的左区间长
            count = 1
            while tmp_left:
                if i < tmp_left[-1][0]:
                    count += tmp_left[-1][1]
                    tmp_left.pop()
                else:
                    break
 
            tmp_left.append((i, count))
            print('tmp_left',tmp_left)
            left.append(count)

        print(left)
 
        for i in reversed(A):           #统计当前数为最小值的右区间长,右小等会翻转左小
            count = 1
            while tmp_right:
                if i <= tmp_right[-1][0]:
                    count += tmp_right[-1][1]
                    tmp_right.pop()
                else:
                    break
 
            tmp_right.append((i, count))
            right.append(count)
 
        right.reverse()
        print(right)
 
        result = 0
 
        for i in range(len(A)):
            print(A[i] * left[i] * right[i]) #当前值* 以当前值为最小值的区间个数
            result += A[i] * left[i] * right[i] 
 
        return result % mod


Solution().sumSubarrayMins([3,1,2,4])

 

23、螺旋遍历一个矩阵
Input:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
Output: [1,2,3,6,9,8,7,4,5]
Example 2:
Input:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
Output: [1,2,3,4,8,12,11,10,9,5,6,7]

思路:
0, 0开始走,
right -> down,
down -> left,
left -> up,
up -> right.
每走过一点,将值添加到结果中,走过的点记为 'x'。当四周都是 'x' 或边界时结束。

def checkStop(matrix, x, y):
    t = [(x+1, y),
         (x-1, y),
         (x, y+1),
         (x, y-1),
         (x, y)]
    for i in t:
        try:
            if i[1] < 0 or i[0] < 0:
                continue
                
            if matrix[i[1]][i[0]] != 'x':
                return False
        except IndexError:
            continue
    else:
        return True
    
    
class Solution(object):
    def right(self, matrix, x, y, result, stop):
        if checkStop(matrix, x, y):
            return result
        while 1:
            try:
                # matrix
                if matrix[x][y]== 'x':
                    raise IndexError
                result.append(matrix[x][y])
                matrix[x][y] = 'x'
                y += 1

            except IndexError:
                y -= 1
                return self.down(matrix, x+1, y, result, stop)
    
    def down(self, matrix, x ,y, result, stop):
        if checkStop(matrix, x, y):
            return result
        while 1:
            try:
                # matrix
                if matrix[x][y] == 'x':
                    raise IndexError
                result.append(matrix[x][y])
                matrix[x][y] = 'x'
                x += 1
            except IndexError:
                x -= 1
                return self.left(matrix, x, y-1, result, stop)
    
    def left(self, matrix, x, y, result, stop):
        if checkStop(matrix, x, y):
            return result
        while 1:
            try:
                # matrix
                if matrix[x][y] == 'x' or x < 0:
                    raise IndexError
                result.append(matrix[x][y])
                matrix[x][y] = 'x'
                y -= 1
            except IndexError:
                y += 1
                return self.up(matrix, x-1, y, result, stop)
    
    def up(self, matrix, x, y, result, stop):
        if checkStop(matrix, x, y):
            return result

        while 1:
            try:
                # matrix
                if matrix[x][y] == 'x' or y < 0:
                    raise IndexError
                result.append(matrix[x][y])
                matrix[x][y] = 'x'
                x -= 1
            except IndexError:
                x += 1
                return self.right(matrix, x, y+1, result, stop)
    
    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        x, y = 0, 0
        
        result = []
        # right -> down
        # down -> left
        # left -> up
        # up -> right
        stop = {}
        return self.right(matrix, 0, 0, result, stop)


a=Solution().spiralOrder([
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
])
print(a)

23、两链表之和

Input: (6 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 6 -> 8 -> 0 -> 7

思路:  若用栈的方式,要占用额外空间,因此考虑用字符串来存储值

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        num1 = ""
        num2 = ""
		# loop through the first linked list, storing the values in the num1 variable
        while l1 is not None:
            num1 += str(l1.val)
            l1 = l1.next
		# follows same process as above
        while l2 is not None:
            num2 += str(l2.val)
            l2 = l2.next
		# calculate the sum of the values that we just obtained and store it as a string
        summation = str(int(num1) + int(num2))
		# make the head of the node the first number in the summation string
        head = ListNode(summation[0])
		# create a new reference to the head so we can manipulate the linked list but not lose the original reference to the head
        temp = head
		# loop through the remaining numbers in the summation string, each time creating a new node
        for val in summation[1:]:
            temp.next = ListNode(val)
            temp = temp.next
		# return the original reference to the head
        return head

24、链表xiang节点

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3
begin to intersect at node c1.

 

class Node:
    def __init__(self,x):
        self.next=None
        self.val=x

class Solution:
    def find_similar_node(self,l1,l2):
        p=l1
        q=l2
        if not p or not q:
            return None
        while p!=q:
            if p==None:
                return l2
            if q==None:
                return l1
            q=q.next
            p=p.next
        return p

26、链表中第K大元素

 

27、第K大的数
Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

class Solution:
# @param {integer[]} nums
# @param {integer} k
# @return {integer}
    def findKthLargest(self, nums, k):
        tmp=nums[0]
        large=[v for v in nums if v>tmp]
        small=[m for m in nums if m<tmp]
        equal=[n for n in nums if n==tmp]

        if len(large)>=k:             #最大第K个数,所以从最大检索
            return self.findKthLargest(large,k)
        if k-len(large)<=len(equal):
            return equal[0]
        return self.findKthLargest(small,k)


a=Solution().findKthLargest([3,2,3,1,2,4,5,5,6] ,4)
print(a)

 

28、八皇后问题

在一个8*8棋盘上,每一行放置一个皇后旗子,且它们不冲突。冲突定义:同一列不能有两个皇后,每一个对角线也不能有两个皇后。当然,三个皇后也是不行的,四个也是不行的

import random
#随机模块

def conflict(state,col):
    #冲突函数,row为行,col为列
    row=len(state)  #目前没冲突列表的长度row
    for i in range(row):
        if abs(state[i]-col) in (0,row-i):#重要语句  ,.如果row+1行皇后所在的列col与其他行皇后的列相同或处于对角线,则冲突
            #col 代表当前时刻皇后所在列数,state[i]代表历史时刻皇后所在列数,abs(state[i]-col)为列数差,当abs(state[i]-col)==0:乃是同列  当abs(state[i]-col)《行数差,表示同对角线

            # row表示当前时刻已经迭代次数(行数),row-i 表示当前行和元祖某行的行数差距(由于,不在同列或对角线要求为,当前皇后所在一定不是
            #例:第一行与第二行,列数差在(0,1)间,一定是同列或者同对角线
            return True
    return False
    
def queens(num=8,state=()): #迭代器的元素放在元组中,意味不可变
    #生成器函数
    for pos in range(num):
        if not conflict(state, pos):
            if len(state)==num-1:   #到达最后一行
               # print('pos',pos)
                yield(pos,)   #(0, 4, 7, 5, 2, 6, 1, 3)  中的(3,)
            else:
                tmp=queens(num,state+(pos,))  #递归,结束条件,是从最后一行向一行跑,
                for result in tmp:   #从结果返回
                    print('result',result)
                    yield (pos,)+result   #进入下一行,迭代器的递归

# def queenprint(solution):
#     #打印函数
#     def line(pos,length=len(solution)):
#         return '. '*(pos)+'X '+'. '*(length-pos-1)
#     for pos in solution:
#         print (line(pos))
        

for solution in queens(8):
    print(solution)
    
print ('  total number is '+str(len(list(queens()))))  #迭代器中元祖长度
print ('  one of the range is:\n')
#queenprint(random.choice(list(queens())))

 

29、链表环

判断一个链表是否为一个链表环

思路: 快慢法

class Solution(object):
    def hasCycle(self, head):

        if not head:
            return False

        two_head = head.next

        if not two_head:
            return False

        while head and two_head:

            if head == two_head:
                return True

            head = head.next
            try:
                two_head = two_head.next.next  #这样写时间上小号更少
            except:
                return False

        return False

30、增高天际线

输入: grid = [[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]]
输出: 35
解释: 
The grid is:
[ [3, 0, 8, 4], 
  [2, 4, 5, 7],
  [9, 2, 6, 3],
  [0, 3, 1, 0] ]

从数组竖直方向(即顶部,底部)看“天际线”是:[9, 4, 8, 7]
从水平水平方向(即左侧,右侧)看“天际线”是:[8, 7, 9, 3]

在不影响天际线的情况下对建筑物进行增高后,新数组如下:

gridNew = [ [8, 4, 8, 7],
            [7, 4, 7, 7],
            [9, 4, 8, 7],
            [3, 3, 3, 3] ]

 

思路: 得到的新数组中每个元素,为原来行最大值和列最大值中的较小的一个

class Solution(object):
    def maxIncreaseKeepingSkyline(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        length = len(grid[0])
        
        # Get line max.
        line_dict = {str(index):max(data) for index, data in enumerate(grid)}
        print(line_dict)
        # Get column max.
        column_dict = {str(index):max((grid[index2][index] for index2 in range(len(grid)))) for index in range(length)}
        print(column_dict)
        total_increases = 0
        
        for index, line in enumerate(grid):
            for index2, cell in enumerate(line):  #cell为当前点的值,min([line_dict[str(index)], column_dict[str(index2)]])为改变后的值
                total_increases += min([line_dict[str(index)], column_dict[str(index2)]]) - cell
        
        return total_increases
a=Solution().maxIncreaseKeepingSkyline([[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]])

 

31、两个排序后数组的中位数

Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

 

思路:每次丢弃k//2 个最小元素,将前k-1个元素去掉

 

class Solution(object):

    def findMedianSortedArrays(self, nums1, nums2):

        k = len(nums1) + len(nums2)
        if k <= 2:
            return sum(nums1+nums2) / k
        raw_k = k

        k = k // 2
        print(k)

        if raw_k % 2 != 0:     #列表长为奇数时,返回中间索引+1(由于是向下取整 )
            k += 1

        while k > 1:      #由于循环每次 k=k-k//2 ,k最小为1 ,若玄幻条件 k>0 ,会进入死循环
            print('k',k)
            tmp = k // 2
            if nums1:
                if tmp > len(nums1):
                    tmp = len(nums1)
            if nums2:
                if tmp > len(nums2):
                    tmp = len(nums2)

            nums1_k_value = nums1[tmp-1] if nums1 else float('inf')#返回两个列表第k//2值小
            print('nums1_k_value',nums1_k_value)
            nums2_k_value = nums2[tmp-1] if nums2 else float('inf')

            if nums1_k_value < nums2_k_value: #两个列表谁的第k//2位置上的值小,对那个数组进行操作
                nums1 = nums1[tmp:]
            else:
                nums2 = nums2[tmp:]
            print(nums1,nums2)

            k -= tmp



        result = sorted(nums1[:2] + nums2[:2])
        if raw_k % 2 != 0:
            return result[0]

        return sum(result[:2]) / 2

a=Solution().findMedianSortedArrays([1, 2, 4, 6,8],[3, 5, 7, 9])
print(a)

 

 

 

32、未排序数组中第k个大的数

Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.
思路:利用快排

class Solution:
    def findKthLargest(self, nums, k):
        low = 0
        high = len(nums) - 1
        return self.Quicksort(nums, low, high, k)

    def Quicksort(self, nums, low, high, k):
        if low > high:
            return -1
        mid = self.partition(nums, low, high)
        if mid == k - 1:
             return nums[mid]
        elif mid < k - 1:
            return self.Quicksort(nums, mid + 1, high, k)
        else:
            return self.Quicksort(nums, low, mid - 1, k)
        #self.Quicksort(nums, mid + 1, high, k)
        #self.Quicksort(nums, low, mid - 1, k)
        #return -1


    def partition(self, nums, low, high):
        left = low
        right = high
        key = nums[high]
        while left < right: #复杂度高
            while left < right and nums[left] >= key : #最好以右边开始
                left += 1
            while left < right and nums[right] <= key:
                right -= 1
            if left < right:
                nums[left], nums[right] = nums[right], nums[left]
        nums[right], nums[high] = nums[high], nums[right]
        return right
a=Solution().findKthLargest(nums=[3,2,3,1,2,4,5,5,6],k=2)
print(a)

33、合并两个排序过的列表

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

 

思路:利用双指针

 

class Solution:
    def find_mid(self,list1,list2):
        p=q=Node(0)


        while list1 and list2:
            if list1.val<list2.val:
                p.next=list1
                list1=list1.next
            else:
                p.next=list2
                list2=list2.next
            p=p.next
        if list1:
            p.next=list1
        if list2:
            p.next=list2
        return q.next


34、合并排序的数组
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3
Output: [1,2,2,3,5,6]
合并两个排序过的整数数组。

 

思路:利用已知的m+n一定为最后输出列表的长度

 

class Solution:
    def merge(self,nums1,nums2,m,n):
        while m>0 and n>0:
            if nums1[m-1]>nums2[n-1]:  #m-1 ,n-1是由于list长未(0,len(list)-1)
                nums1[m+n-1]=nums1[m-1]
                m-=1
            else:
                nums1[m+n-1]=nums2[n-1]
                n-=1
            print(nums1)
        if m>0:
            nums1[m+n-1]=nums1[m-1]
        if n>0:
            nums1[m+n-1]=nums2[n-1]
        return nums1

a=Solution().merge( [1,2,3,0,0,0], [2,5,6],3,3)
print(a)


 

35、两个列表的(相同部分)最小索引和

假设Andy和Doris想要选择一家餐馆吃晚餐,他们都有一个最受欢迎的餐馆列表。
你需要用最少的列表索引总和帮助他们找出他们的共同兴趣。
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
Output: ["Shogun"]
Explanation: The only restaurant they both like is "Shogun".
Example 2:
Input:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]
Output: ["Shogun"]
Explanation: 索引总和最小

class Solution:
    def findRestaurant(self, list1, list2):
        list1_dict = {value:index for index, value in enumerate(list1)}
        res_dict = {}
        for index, value in enumerate(list2):
            if value in list1_dict:
              #  print(list1_dict[value])
                #print(list1_dict.get(value))
                res_dict[index+list1_dict[value]]=value

        return res_dict[min(res_dict)]


a=["Shogun", "Tapioca Express", "Burger King", "KFC"]
b=["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
c=print(Solution().findRestaurant(a,b))

 

36、2D矩阵搜索

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
Output: true
Example 2:
Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
Output: false
思路: 利用两个二分查找 定位行 后再定位列,耗时最少

class Solution(object):
    def binarySearch(self, rawList, target, index=0):  #二分法定位target所在区间

        if target >= rawList[-1]:
            return len(rawList) - 1

        if target < rawList[0]:
            return -1

        split = len(rawList) // 2

        leftList = rawList[:split]
        rightList = rawList[split:]


        if leftList[-1] <= target and rightList[0] > target:
            return len(leftList) + index - 1

        if rightList[0] == target:
            return len(leftList) + index

        if leftList[-1] > target:
            return self.binarySearch(leftList, target, index=index)

        if rightList[0] < target:
            return self.binarySearch(rightList, target, index=index+len(leftList))

    def binarySearch2(self, rawList, target):  #查找二分法
        low=0
        high=len(rawList)
        while low<high:
            mid=low+(high-low)//2
            if rawList[mid]==target:
                return True
            if target>rawList[mid]:
                low=mid+1
            else:
                high=mid
        return False


    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        if not any(matrix):
            return False

        column = [i[0] for i in matrix]
        print(column)

        column_result = self.binarySearch(column, target)
        if column_result == -1:
            return False

        return self.binarySearch2(matrix[column_result], target)

a=Solution().searchMatrix(matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
],target = 3)
print(a)

37、多重三数相加

Input: A = [1,1,2,2,3,3,4,4,5,5], target = 8
Output: 20
Explanation: 
Enumerating by the values (A[i], A[j], A[k]):
(1, 2, 5) occurs 8 times;      # 2*2*2
(1, 3, 4) occurs 8 times;      #2*2*2
(2, 2, 4) occurs 2 times;       #2*(2-1)*2
(2, 3, 3) occurs 2 times.       #2*(2-1)*2
Example 2:
Input: A = [1,1,2,2,2,2], target = 5
Output: 12
Explanation: 
A[i] = 1, A[j] = A[k] = 2 occurs 12 times:         
We choose one 1 from [1,1] in 2 ways,
and two 2s from [2,2,2,2] in 6 ways.

 

class Solution(object):
    def threeSumMulti(self, A, target):
        mod=10**9+7
        res=0
        a=A
        d={}
        for i in a:
            if i in d:
                d[i]+=1
            else:
                d[i]=1
        print('d',d)
        for i in d:
           # print(i)
            for j in d:
                if i==j or target-i-j==i or target-i-j==j or target-i-j not in d:
                    print('i','j',i,j)
                    continue
                res+=d[i]*d[j]*d[target-i-j]           #满足条件的三个数都不同
                print('res',res)
        res//=6    #每个数字都循环了两次,每个满足条件的数字对应3个数,因此除以6 去掉重复
#        print(res)
        for i in d:
            if d[i]<2 or target-i-i==i or target-i-i not in d:
                continue
            res+=(d[i]*(d[i]-1)//2)*d[target-i-i]       #满足条件的两个数不同
#        print(res)
        for i in d:
            if d[i]<3 or target!=i*3:
                continue
            res+=d[i]*(d[i]-1)*(d[i]-2)//6              #一个数即可满足条件
        
        
        return res%mod
    
s=Solution()
print(s.threeSumMulti(A = [1,1,2,2,3,3,4,4,5,5], target = 8))

 

38、二叉树最大深度

Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its depth = 3.
找到二叉树的最大深度。

class Solution(object):
    def max_deep(self,root):
        return max(self.max_deep(root.left),self.max_deep(root.right))+1 if root else 0

 

或者:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if root:
            t=self.maxDepth(root.left)+1
            m=self.maxDepth(root.right)+1
            return max(t,m)
        else:
            return 0
        


39、给定n个整数的数组nums,是否有元素a,b,c在nums中,a + b + c = 0?找到数组中所有唯一的三元组,它们的总和为零。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        dic={}                      #统计重复
        for index in nums:
            if index in dic:
                dic[index]+=1
            else:
                dic[index]=1


        nums = sorted(set(nums))
        print('nums',nums)

        res = []
        for i, data in enumerate(nums):       #当不重复时 将满足结果的元素保存在新列表中
            if data > 0:
                break
            target =  - data
            start = i + 1
            end = len(nums) - 1
            while start < end:
                if nums[start] + nums[end] == target:
                    res.append([nums[start], nums[end], data])
                    end -= 1
                    start += 1
                    continue
                if nums[start] + nums[end] > target:
                     end -= 1
                else:
                   start+=1

        if 0 in dic and dic[0]>=3:        #3个重复元素为0时
            res.append([0,0,0])
        for j in dic.keys():              #2个重复元素不为0时
            if j!=0 and dic[j]>=2 and -2*j in dic:
                res.append([j,j,-2*j])
        return res






40、最大利润

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
             Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Example 2:
Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
             engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
 

class Solution(object):
    def maxProfit(self, nums):
        profit=0
        state=0
        buy=0

        for i in range(len(nums)-1):
            if nums[i+1]>nums[i] and state==0:
                buy=nums[i]
                state=1
            if nums[i]>nums[i+1] and state==1:
                profit+=nums[i]-buy
                state=0
        if state==1:
            profit+=(nums[-1]-buy)
        if state==0 and buy==0:
            return 0


        return profit




a= [7,1,5,3,6,4]
b=Solution().maxProfit(a)
print(b)

40、子集(回溯)

Example:
Input: nums = [1,2,3]
Output:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
直接上递归,每条线都有两个决策:
1. 加上。
2. 不加。

class Solution(object):
    def subsets(self, nums):
        result = []


        def maybe(i, state):
            if i == len(nums):
                return

            result.append(state+[nums[i]])

            maybe(i+1, state+[nums[i]])  #横向递归 ,当i+1==len(nums)返回,有[[1], [1, 2], [1, 2, 3]]
            maybe(i+1, state)               #纵向递归  i=2时,将子集加入列表(通过state)


        maybe(0, [])

        return result+[[]]

a=Solution().subsets([1,2,3])
print(a)
nums = [1,2,3]
a=Solution().subsets(nums)
print(a)

 

41、二进制子数组和

在0和1的数组A中,有多少非空子数组具有和S?

Example 1:
Input: A = [1,0,1,0,1], S = 2
Output: 4
Explanation: 
The 4 subarrays are bolded below:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
 
Note:
A.length <= 30000
0 <= S <= A.length
A[i] is either 0 or 1.

思想:  用字典统计历史累和情况,当目标值与累和差在历史统计字典中时,表示,去掉该历史,亦满足

class Solution(object):
    def count_includ(self,nums,S):
        dic={0:1}
        res=0
        sum=0
        for value in nums:
            sum+=value

            res+=dic[sum-S] if sum-S in dic else 0#当历史累和大于等于S 时,会有其个数中可能,思想: 当累和与S差值1时,历史统计共有2个1,则表示共有两种情况将1 去掉后,其差为0,满足条件
            #等于时  1 、 [1,0,1]  2、[1,0,1,0]    大于时  1、[0,1,0,1]  2、[1,0,1]
            dic[sum]=dic[sum]+1 if sum in dic else 1
            print(dic)
        
        return res

a=Solution().count_includ([1,0,1,0,1], S = 2)
print(a)

42、加油站

沿着环形路线有N个加油站,其中站i的气体量是气体[i]。
你有一辆带有无限油箱的汽车,从车站i到下一站(i + 1)需要花费成本[i]。您可以在其中一个加油站开始使用空罐。
如果您可以顺时针方向绕电路一次返回起始加油站的索引,否则返回-1。
输入: 
气体= [1,2,3,4,5]
费用= [3,4,5,1,2]
输出:3
说明:
从3号站(索引3)开始,加满4个气体。你的坦克= 0 + 4 = 4
前往车站4.您的坦克= 4  -  1 + 5 = 8
前往车站0.您的坦克= 8  -  2 + 1 = 7
前往车站1.您的坦克= 7  -  3 + 2 = 6
前往车站2.您的坦克= 6  -  4 + 3 = 5
前往车站3.费用为5.您的汽油足以返回3号站。
因此,返回3作为起始索引。
例2:
输入: 
气体= [2,3,4]
费用= [3,4,3]
输出:-1
说明:
您无法从0号站或1号站开始,因为没有足够的天然气可以前往下一站。
让我们从2号站开始,填满4个单位的天然气。你的坦克= 0 + 4 = 4
前往车站0.您的坦克= 4  -  3 + 2 = 3
前往车站1.您的坦克= 3  -  3 + 3 = 3
你不能回到2号站,因为它需要4个单位的燃气,但你只有3个。
因此,无论您从哪里开始,都无法绕过电路。

思想: 若汽油和大于消费和,则一定有目标站点出现,所以遍历一次即可(排除法)

class Solution(object):
    def canCompleteCircuit(self, gas, cost):
        if sum(gas)<sum(cost):
            return -1
        profit=0
        label=True
        record=0
        for i in range(len(gas)):  #循环一次就能找到起点,由于sum(gas)<sum(cost) 证明了 一定存在这个点
            if profit+gas[i]-cost[i]>0:
                profit=profit+gas[i]-cost[i]
                if label:               #设置标志位来记录
                    record=i
                    label=False
            else:
                profit=0
                label=True
        return record


if __name__ == '__main__':
    gas  = [1,2,3,4,5]
    cost = [3,4,5,1,2]
    a=Solution().canCompleteCircuit(gas,cost)
    print(a)

43、您将获得一个整数数组nums,您必须返回一个新的计数数组。counts数组具有其中count [i]是nums [i]右边的较小元素的数量的属性。
例:
输入:[5,2,6,1]
产出:[2,1,1,0] 
说明:
在5的右边有2个较小的元素(2和1)。
在2的右边,只有一个较小的元素(1)。
在6的右边有1个较小的元素(1)。
在1的右边有0个较小的元素。
思路:
二分。
瓶颈依然在于插入列表中的时候需要的时间复杂度为O(n)。

思想:找到该数右边小于他的元素个数(翻译:从右向左,该数左端小于它的元素个数,即符合插入思想。且最后一个元素,一定为0),利用插入法,依次按断

class Solution(object):
    # def bisect_left(self,a, x, lo=0, hi=None):
    #     if lo < 0:
    #         raise ValueError('lo must be non-negative')
    #     if hi is None:
    #         hi = len(a)
    #     while lo < hi:
    #         mid = (lo+hi)//2
    #         if a[mid] < x: lo = mid+1
    #         else: hi = mid
    #     return lo
    def insort_left(self,nums, i):
        left=0
        right=len(nums)
        while left<right:
            mid=left+(right-left)//2
            if nums[mid]<i:
                left=mid+1
            else:
                right=mid            #找左边,等号移动右指针
        nums.insert(left,i)
        return left



    def countSmaller(self, nums):    #该数右边比它小的个数等于倒置后,左边比他小的个数
        x = []
        result = []
        for i in nums[::-1]:
            #print('x',x,'i',i)

            #result.append(self.bisect_left(x, i))
            #print(result)

            lo=self.insort_left(x,i)  #思想:依次插入当前数,当前数的序号就是其与前面数的比较大小的结果
            result.append(lo)
        return result[::-1]


a=Solution().countSmaller([5,2,6,1])
print(a)

 

43、我们有一些[0,1,...,N  -  1]的置换A,其中N是A的长度。
(全局)反转的数量是i <j的数量,其中0 <= i <j <N且A [i]> A [j]。
局部反演的数量是i的数量,其中0 <= i <N且A [i]> A [i + 1]。
当且仅当全局反转的数量等于本地反转的数量时才返回true。
例1:
输入:A = [1,0,2]
输出:true
说明:全局反演1次,局部反演1次。
例2:
输入:A = [1,2,0]
输出:false
说明:有2个全局反转,1个本地反转。
注意:
A将是[0,1,...,A.length  -  1]的排列。
A的长度范围为[1,5000]。
此问题的时间限制已减少。

题目理解: 原数组为升序,相邻元素变化为降序就是本地翻转 ,不相邻元素变化为全局翻转

           例如:【0,1,2】 本地旋转有两种: 【1,0,2】【0,2,1】剩下都是全局

 

44、变位词

Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

 

class Solution(object):
    def sort(self,s1):
       # print(s1)
        if len(s1)<=1:
            return s1
        mid=len(s1)//2
        left=self.sort(s1[:mid])
        right=self.sort(s1[mid:])
        return self.merge(left,right)

    def merge(self,left,right):
        l,r=0,0
        res=''
        while l<len(left) and r<len(right):
            if ord(left[l])<ord(right[r]):
                res+=left[l]
                l+=1
            else:
                res+=right[r]
                r+=1
        res+=left[l:]
        res+=right[r:]
        return res

    def groupAnagrams(self, nums):
        dic={}
        for value in nums:
           # print('value',value)
            label=self.sort(value)
            if label in dic:
                dic[label].append(label)
            else:
                dic[label]=[value]
        return dic.values()




a=Solution().groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])
print(a)

 

45、两数组的重叠部分

Example 1:
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2]
Example 2:
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [9,4]
思路: & 交集, | 并集,^ 并集-交集

set(nums1)&set(nums2)

 

45、两数组重叠部分II

Example 1:
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2,2]
Example 2:
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [4,9]

思路:排序+双指针

class Solution(object):
    def intersect(self, nums1, nums2):
        result = []
    
    
        nums1.sort()
        nums2.sort()
        
        l1 = 0
        l2 = 0
        
        l1_length = len(nums1)
        l2_length = len(nums2)
        
        while l1 < l1_length and l2 < l2_length:
            if nums1[l1] == nums2[l2]:
                result.append(nums1[l1])
                l1 += 1
                l2 += 1
            
            elif nums1[l1] < nums2[l2]:
                l1 += 1
            else:
                l2 += 1
        
        return result   

 

46、可被模板替换的字符串

Example 1:
Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
Output: ["mee","aqq"]

说明:  abb模式有 mee ,  aqq 等

class Solution(object):
    def findAndReplacePattern(self, words, pattern):
        def translate_pattern(word):
            label=[0]*len(word)
            for i in range(len(word)-1):
                if word[i]==word[i+1]:
                    label[i]=1
                    label[i+1]=1

            return label
        
        x = translate_pattern(pattern)
        print(x)

        result = []
        for i in words:
            if x == translate_pattern(i):
                result.append(i)
        
        return result
a=Solution().findAndReplacePattern(["abc","deq","mee","aqq","dkd","ccc"],"abb")
print(a)

 

47、根据前序和后序的结果生成二叉树

返回与给定的前序和后序遍历匹配的任何二叉树。
前后遍历中的值是不同的正整数。
 
例1:
输入:pre = [1,2,4,5,3,6,7],post = [4,5,2,6,7,3,1]
产出:[1,2,3,4,5,6,7]
思想: 先序 后的数组一定是   [ root , 根的左树群,根的右树群]

           后序后的数组一定是     [根的左树群,根的右树群,root] 

树思想: 先构建根,再构建根左节点,根右节点,判断(当存在时):递归构建剩下


注意:
1 <= pre.length == post.length <= 30
pre []和post []都是1,2,...,pre.length的排列。
保证答案存在。如果存在多个答案,您可以返回任何答案。
根据二叉树的前序和后序遍历,返回一颗完整的二叉树。
不唯一,返回随便一个即可。
思路:
1.二叉树的前序是根左右。
2.二叉树的后序是左右根。
在前序中确定根,然后在后序中找左右子树。
pre = [1,2,4,5,3,6,7]
post = [4,5,2,6,7,3,1]

 

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def constructFromPrePost(self, nums1, nums2):
        root = TreeNode(nums1[0])

        def getLeftAndRight(pre, post):            
            # no more node.
            if not pre:
                return None
            
            index = post.index(pre[0])
            
            # post left tree
            post_left = post[:index+1]
            post_right = post[index+1:-1]
            t = len(post_left)

            pre_left = pre[:t]
            pre_right = pre[t:-1]

            left = pre_left[0]
            right = pre_right[0] if post_right else None

            return (left, right, pre_left, post_left, pre_right, post_right)
            
        def construct(root, nums1, nums2):
            x = getLeftAndRight(nums1[1:], nums2)
            if root and x:
                if x[0] is not None:
                    root.left = TreeNode(x[0])
                if x[1] is not None:
                    root.right = TreeNode(x[1])

                if root.left:
                    construct(root.left, x[2], x[3])

                if root.right:
                    construct(root.right, x[4], x[5])
            

        construct(root, nums1, nums2)
        
        return root

https://leetcode.com/contest/weekly-contest-98/problems/construct-binary-tree-from-preorder-and-postorder-traversal/

 

48、转换已排序的数组到二叉搜索树

一个升序数组,变为平衡二叉树

思路:可以将它看做是一颗二叉搜索树(大小排序:左树,root,右树)中序遍历后的结果

https://leetcode.com/problems/validate-binary-search-tree/description/

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        if not nums:
            return None
        mid=len(nums)//2
        
        root=TreeNode(nums[mid])
        left=nums[:mid]
        right=nums[mid+1:]

        if left:
            root.left=self.sortedArrayToBST(left)
        if right:
            root.right=self.sortedArrayToBST(right)
        return root
       

49、 二叉搜索树的后序遍历序列

判断给定的整数数组是不是二叉搜索树的后序遍历序列

思路:后序遍历,root在最后,且二叉搜索树其左树区间一定全部小于root,右树区间一定全部大于root,

 树思想: 先判断整体满足条件,再利用指针找到第一个右子树节点,后递归判断每个子数组(分成左右两端两个子数组了,此时应设置标志位)。         

def is_post_order(order):
    length = len(order)
    if length:
        root = order[-1]
        left = 0
        while order[left] < root: #左树都小于root
            left += 1
        right = left  #此时order[left] >= root, 因此直接赋予而不用right = left+1
        while right < length - 1:
            if order[right] < root:
                return False
            right += 1
        label_left= True if left == 0 else is_post_order(order[:left])  #每个子树也需要符合 左 中 右 大小排序
        label_right= True if left == right else is_post_order(order[left:right]) 
        return left_ret and right_ret
    return False

50、有效的二叉搜索树  (左树<  根  < 右树 )

验证是否为二叉搜索树  

Input:
    2
   / \
  1   3
Output: true
Example 2:
    5
   / \
  1   4
     / \
    3   6
Output: false

https://leetcode.com/problems/validate-binary-search-tree/description/

思路: 中序搜索后数组为递增数组即满足

树思想:利用临时变量来记录前一个根值。

 

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isValidBst(self,root):
        if not root:
            return True
        self.tmp=float('-inf')            #设置一个标志数,由于要求后方为升序,因此设置为最小值
        
        def ok(root):
            if root.left:
                if ok(root.left)==-1:
                    return -1
            if root.val <= self.tmp:      #此时利用 中序 查找 与上一时刻值进行比较 ,要求升序
                return -1
            
            self.tmp=root.val
            
            if root.right:
                if ok(root.right)==-1:
                    return -1
            return 
        if ok(root)==-1:
            return False
        return True


51、跳跃游戏.

给定一个非负整数数组,您最初定位在数组的第一个索引处。
数组中的每个元素表示该位置的最大跳转长度。
确定您是否能够到达最后一个索引。
例1:
输入:[2,3,1,1,4]
输出:true
说明:从索引0跳转1步到1,然后从最后一个索引跳3步。
例2:
输入:[3,2,1,0,4]
输出:false
说明:无论如何,您总是会到达索引3。它的最大值
             跳转长度为0,这使得无法到达最后一个索引。
 

class Solution(object):
   # def is_jump(self,):
    def canJump(self, nums):
        tmp_max=0
        record=0
        for index ,value in enumerate(nums):
            if tmp_max>=len(nums)-1:
                return True
            record=max(record,index+value)
            if tmp_max==index:
                tmp_max=record
        return False
            
a=Solution().canJump([1,0,1,1,4])
print(a)

 

52、跳跃游戏2

输入:[2,3,1,1,4]
输出:2
说明:到达最后一个索引的最小跳转次数为2。
    从索引0到1跳1步,然后从最后一个索引跳3步。
注意:
您可以假设您始终可以到达最后一个索引。
与1差不多,这个需要返回的是最少的可用步数。

 

class Solution(object):
    def jump(self, nums):
        max_reach, next_max_reach, count = 0, 0, 0
        for index, value in enumerate(nums):
            if max_reach >= len(nums) - 1:                        #当前距离能够跳出列表
                return count
            next_max_reach = max(next_max_reach, index + value)     #记录经过的index + value 最大者
           # print(next_max_reach)
            if index == max_reach:                              #表示当前元素能够走的最远距离,如果在这个过程中,有index + value> len(nusm)-1 说明可以结束
                print(index)
                count, max_reach = count + 1, next_max_reach

a=Solution().jump([2,1,1,1,4])
print(a)

 

 

53、距离最近的人的可走过的最远距离

https://leetcode.com/contest/weekly-contest-88/problems/maximize-distance-to-closest-person/

在一排座位中,1表示坐在该座位上的人,0表示座位是空的。 
至少有一个空座位,至少有一个人坐着。
亚历克斯想坐在座位上,以便他和最亲近的人之间的距离最大化。 
返回距离最近的人的最大距离。

例1:
输入:[1,0,0,0,1,0,1]
输出:2
说明: 
如果亚历克斯坐在第二个开放座位(座位[2]),那么最近的人有距离2。
如果Alex坐在任何其他开放式座位上,则最亲近的人的距离为1。
因此,到最近的人的最大距离是2。
例2:
输入:[1,0,0,0]
输出:3
说明: 
如果Alex坐在最后一个座位上,那么最近的人就是3个座位。
这是可能的最大距离,所以答案是3。
注意:
1 <= seats.length <= 20000
席位仅包含0或1,至少一个0,至少一个1。


题意:Alex要坐在任意一个0上,问坐在哪个点上距离最近的1是最远的。

转换: 返回某0变为‘1’时,返回它距离它最近‘1’的距离
 

class Solution(object):
    def maxDistToClosest(self, nums):
        indexes = [i for i in range(len(nums)) if nums[i] == 1]
        # if len(indexes)==1:
        #     return len(nums)-indexes[-1]-1
        tmp=0
        for i in range(len(indexes)-1):     #中间为0
            dis=indexes[i+1]-indexes[i]
            tmp=max(tmp,dis)

        tmp=tmp//2
        print(tmp)
        if indexes[-1]!=len(nums)-1:  #考虑[1,0,0,0,0]的情况   右为0
            tmp=max(tmp,len(nums)-1-indexes[-1])
        print(tmp)
        if indexes[0]!=0:
            tmp=max(tmp,indexes[0])    #考虑[0,0,1*]情况   左为0


        return tmp





a=Solution().maxDistToClosest([0,1,1,0,1,1,0,1])
print(a)

52、子数组的最大和

1.与当前值比(确定历史和大于0)  2、与历史比

class Solution(object):
    def subsets(self, nums):
        tmp=nums[0]
        res=nums[0]

        for i in nums[1:]:
            tmp=max(i+tmp,i)  #判断最大区间是加上当前值,还是重新从当前值开始计算 PS:可以避免历史和是负数
            res=max(res,tmp)  #历史最大值和当前最大值比较
        return res

a=Solution().subsets([3,-1,2,-1])
print(a)

53、循环子数组的最大和

思路:  收尾相连=sum(nums) - sum(min A[subarray])

class Solution(object):
    def maxSubarraySumCircular(self, nums):
       # dp = [A[0]]
        tmp=nums[0]
        maxes = nums[0]
        for i in nums[1:]:
            tmp=max(tmp+i,i)
            maxes=max(maxes,tmp)
        print(maxes)

        if maxes < 0:
            return maxes

        tmp = nums[0]   #最小值
        mines = nums[0]
        for i in nums[1:]:
            tmp=min(tmp+i,i)
            mines=min(mines,tmp)


        maxes = max(maxes, sum(nums) - mines)  #首尾相连的情况其实就是 sum(A) - sum(min A[subarray])  所以,最大值就是正常连续和收尾节点的最大值

        return maxes

a=Solution().maxSubarraySumCircular([5,-3,5])
print(a)

 

54、最小下落路径和

给定一个整数A的正方形数组,我们想要通过A的下降路径的最小和。
下降路径从第一行中的任何元素开始,并从每行中选择一个元素。从上到下,每下层元素可以选择位于它之上的左中右三个元素。
 
例1:
输入:[[1,2,3],[4,5,6],[7,8,9]]
产量:12
说明: 
可能的下降路径是:
[1,4,7],[1,4,8],[1,5,7],[1,5,8],[1,5,9]
[2,4,7],[2,4,8],[2,5,7],[2,5,8],[2,5,9],[2,6,8],[2,6,9]
[3,5,7],[3,5,8],[3,5,9],[3,6,8],[3,6,9]
最小和的下降路径是[1,4,7],所以答案是12。
 
注意:
1. 1 <= A.length == A [0] .length <= 100
2. -1 <= A [i] [j] <= 100
思路:从第二层开始,每个元素都选择位于它之上的三个元素中最小的一个元素。最后输出最后一层中最小的元素即可。

class Solution(object):
    def minFallingPathSum(self, nums):
        for x in range(1, len(nums)):
            for y in range(len(nums[0])):
                a = nums[x-1][y-1] if y-1 >= 0 else float('inf')    #上一行,左列,不存在,则设为无限大
                print(a)
                b = nums[x-1][y+1] if y+1 < len(nums[0]) else float('inf')  #上一行,右列

                nums[x][y] += min(nums[x-1][y], a, b)    #由每个最后元素得到的反演的最小路径

        return min(nums[-1])

a=Solution().minFallingPathSum([[1,2,3],[4,5,6],[7,8,9]])
print(a)

 

55、转换已排序的链表到二叉搜索树

Given the sorted linked list: [-10,-3,0,5,9],
One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:
      0
     / \
   -3   9
   /   /
 -10  5

 

 

56、镜像树

给定二叉树,检查它是否是自身的镜像(即,围绕其中心对称)。
例如,这个二叉树[1,2,2,3,4,3,3]是对称的:
    1
   / \
  2 2
/ \ / \
3 4 4 3
但是以下[1,2,2,null,3,null,3]不是:
    1
   / \
  2 2
   \    \
   3 3
注意:
如果您可以递归和迭代地解决它,那么奖励积分。
判断左子树是否与右子树互为镜像。

思路:1) 判断主树存在   3)判断两树是xiangs

https://leetcode.com/problems/symmetric-tree/submissions/

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isSymmetric(self,root):
        if not root:
            return True
        if self.check(root.left,root.right):
            return True
        return False
        
        
        
    def check(self,left,right):
        if not left and not right:
            return True
        if not left or not right:
            return False
        if left.val!=right.val:
            return False
        return self.check(left.left,right.right) and self.check(left.right,right.left)

 

55、最短路径

给一个二维数组,里面全是非负整数,找到一条左上到右下花费最小的路线。

Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum

 

 

思路:由于 起点在终点的上左,因此,最短路径一定是最后元素上左方向的最小值

class Solution(object):
    def get_up_left(self, x, y):  #由于 起点在终点的上左,因此,最短路径一定是最后元素上左方向的最小值
        if y-1 < 0:
            up = False
        else:
            up = (x, y-1)
        if x-1 < 0:
            left = False
        else:
            left = (x-1,y)
            
        # up and left
        return (up, left)
    
    def minPathSum(self, nums):
  
        
        for i in range(len(nums)):
            for j in range(len(nums[0])):
                xy = self.get_up_left(j, i)
                up = nums[xy[0][1]][xy[0][0]] if xy[0] else float('inf')
                left = nums[xy[1][1]][xy[1][0]] if xy[1] else float('inf')
                
                if up == float('inf') and left == float('inf'):
                    continue
                nums[i][j] +=  min(up, left)
                print(nums)
                
                
        return nums[-1][-1]
a=Solution().minPathSum([
  [1,3,1],
  [1,5,1],
  [4,2,1]
])
print(a)

 

56、单双链表

给一个单链表,将所有的单数节点和双数节点聚合在一块,双数节点跟在单数节点后面。
Example 1:
Input: 1->2->3->4->5->NULL
Output: 1->3->5->2->4->NULL
Example 2:
Input: 2->1->3->5->6->4->7->NULL
Output: 2->3->6->7->1->5->4->NULL

 

class Solution(object):
    def pqList(self, head):
        if not head:
            return head
        p = head
        q = head.next
        q_head = q
        
        while p.next and q.next:
            p.next = p.next.next
            q.next = q.next.next
            
            p = p.next
            q = q.next
            
        p.next = q_head
        
        return head
        

57、解体大数组

给定一个数组A,将其分为左右两个(连续)子阵列,以便:
左边的每个元素都小于或等于右边的每个元素。
左右都是非空的。
left具有尽可能小的尺寸。
在这样的分区之后返回左边的长度。保证存在这样的分区。
 
例1:
输入:[5,0,3,8,6]
输出:3
说明:left = [5,0,3],right = [8,6]
例2:
输入:[1,1,1,0,6,12]
产量:4
说明:left = [1,1,1,0],right = [6,12]

class Solution(object):
    def find_point(self,nums):
        lable=0
        while lable<len(nums):
            if max(nums[:lable+1])<=min(nums[lable+1:]):
                return len(nums[:lable+1])
            lable+=1
        return 0

nums=[1,1,1,0,6,12]
a=Solution().find_point(nums)
print(a)

58、+1

给定表示非负整数的非空数字数组,加上整数的1。
存储数字使得最高有效数字位于列表的开头,并且数组中的每个元素包含单个数字。
您可以假设整数不包含任何前导零,除了数字0本身。
例1:
输入:[1,2,3]
产出:[1,2,4]
说明:数组表示整数123。
例2:
输入:[4,3,2,1]
产出:[4,3,2,2]
说明:数组表示整数4321。

class Solution(object):
    def add_one(self,nums):
        string=''
        for i in nums:
            string+=str(i)
        string=str(int(string)+1)
        dst=[]
        for j in string:
            dst.append(int(j))
        return dst

a=[1,2,3]
print(Solution().add_one(a))

 

58、从已排序的数组中删除重复数据

给定排序的数组nums,就地删除重复项,使每个元素只出现一次并返回新的长度。
不要为另一个数组分配额外的空间,必须通过使用O(1)额外内存修改输入数组来实现此目的。
例1:
鉴于nums = [1,1,2],
你的函数应返回length = 2,nums的前两个元素分别为1和2。
你返回的长度超出了什么并不重要。
例2:
鉴于nums = [0,0,1,1,1,2,2,3,3,4],
你的函数应该返回length = 5,将nums的前五个元素分别修改为0,1,2,3和4。

59、

Remove all elements from a linked list of integers that have value val.
Example:
Input:  1->2->6->3->4->5->6, val = 6
Output: 1->2->3->4->5

class Solution(object):
    def removeElements(self, head, val):
        
        while head:                       #当head值为目标值时
            if head.val == val:
                head = head.next
            else:
                break
        
        _head = head
        
        if not _head:
            return None
        
        while head and head.next:
            if head.next.val == val:
                head.next = head.next.next
            else:
                head = head.next
        return _head

60、

29)奇偶链表

60、旋转列表

Example 1:
Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL
Example 2:
Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL
旋转链表。 k 非负。
k 超过链表的最大长度也可。

思路:快慢指针 (考虑K值大于链表长度时)

class Solution(object):

    def rotateRight(self, head, k):
        if not k or not head:
            return head

        def getLength(node):
            length = 0

            while node:
                node = node.next
                length += 1

            return length

        length = getLength(head)
        k = k % length

        p = head
        tmp=head

        while k > 0:
            p = p.next

            k -= 1

        q=p.next
        dst=q
        p.next=None
        while q:
            q=q.next
        q.next=tmp



        return dst

 

61、三角形最小路径

给定一个三角形,找到从上到下的最小路径总和。您可以移动到下面一行中相邻数字的每一步。
例如,给定以下三角形
[
     [2],
    [3,4],
   [6,5,7]
  [4,1,8,3]
]
从顶部到底部的最小路径总和是11(即,2 + 3 + 5 + 1 = 11)。
注意:
如果能够仅使用O(n)额外空间来执行此操作,则可获得奖励点,其中n是三角形中的总行数。

class Solution:
    def count_min(self,nums):
        length=len(nums)
        for i in range(length-2,-1,-1):   #从下到上一直求最小值的和
            for j in range(len(nums[i])):
                left=nums[i+1][j]
                right=nums[i+1][j+1]
                tmp=min(left,right)

                nums[i][j]+=tmpa
        return nums[0]


nums = [
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]
k = 3
a=Solution().count_min(nums)
print(a)

63、是否是子树

B树是否是A树的子树

 

错误解法

class TreeNode:
    def __init__(self, x=None):
        self.val=x
        self.left=None
        self.right=None

    def is_bisame(self,root1,root2):
        if root1 and root2:
            if root1.val==root2.val:
                return self.check(root1,root2)                   #这种错误了,由于二叉树中不一定仅仅出现一个大小相等的点
            else:
                return  self.is_bisame(root1.left,root2) or self.is_bisame(root1.right,root2)   

    def check(self,root1,root2):
        if not root1:
            return False
        if not root2:
            return True
        if root1.val!=root2.val:
            return False
        return self.check(root1.left,root2.left) and self.check(root1.righr,root2.right)

if __name__ == '__main__':
    node1=TreeNode(8)
    node2 = TreeNode(8)
    node3 = TreeNode(7)
    node4 = TreeNode(9)
    node5 = TreeNode(2)
    node6 = TreeNode(4)
    node7 = TreeNode(7)

    node1.left,node1.right=node2,node3
    node2.left,node2.right=node4,node5
    node5.left,node5.right=node6,node7
#树二
    node8 = TreeNode(8)
    node9 = TreeNode(9)
    node10 = TreeNode(2)

    node8.left, node8.right = node9, node10

    print(TreeNode().is_bisame(node1,node8))

正确解法:
class TreeNode:
    def __init__(self, x=None):
        self.val=x
        self.left=None
        self.right=None
class Solution:
    def is_bisame(self,root1,root2):
        label=False
        if root1 and root2:
            if root1.val==root2.val:
                label= self.check(root1,root2)                   #设置标志位
            if not label:
                label=self.is_bisame(root1.left,root2)
            if not label:
                label=self.is_bisame(root1.right,root2)
        return label

    def check(self,root1,root2):
        if not root2:                #研究了半天,我们必须先判定root2 不能先判定root1 由于,root1和root2同时为Null 条件也成立
            return True
        if not root1:
            return False

        if root1.val!=root2.val:
            return False
        return self.check(root1.left,root2.left) and self.check(root1.right,root2.right)

if __name__ == '__main__':
      # 树1
    node1 = TreeNode(8)
    node2 = TreeNode(8)
    node3 = TreeNode(7)
    node4 = TreeNode(9)
    node5 = TreeNode(2)
    node6 = TreeNode(4)
    node7 = TreeNode(7)

    node1.left, node1.right = node2, node3
    node2.left, node2.right = node4, node5
    node5.left, node5.right = node6, node7

    # 树2
    node8 = TreeNode(8)
    node9 = TreeNode(9)
    node10 = TreeNode(2)

    node8.left, node8.right = node9, node10

    print(Solution().is_bisame(node1, node8))

69、镜像二叉树

给二叉树A ,输出其镜子中的对应二叉树

 思路: 左子树与右子树易位,利用先序输出

class BinartTreeNode:
    def __init__(self,val=None,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right

def MirrorRecurisively(root):
    if root:
        root.left,root.right = root.right,root.left
        MirrorRecurisively(root.left)
        MirrorRecurisively(root.right)

def preOrder(root):
    if root:
        print(root.val,end=' ')
        preOrder(root.left)
        preOrder(root.right)


if __name__ == '__main__':
    node1 = BinartTreeNode(8)
    node2 = BinartTreeNode(6)
    node3 = BinartTreeNode(10)
    node4 = BinartTreeNode(5)
    node5 = BinartTreeNode(7)
    node6 = BinartTreeNode(9)
    node7 = BinartTreeNode(11)

    node1.left,node1.right = node2,node3
    node2.left,node2.right = node4,node5
    node3.left,node3.right = node6,node7

    preOrder(node1)
    print('\n')

    MirrorRecurisively(node1)
    preOrder(node1)

70、螺旋矩阵II

Input: 3
Output:
[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]
 

class Solution:
    def maybe(self,x,y):
        return [(x,y+1),
                (x+1,y),
                (x,y-1),
                (x-1,y)]
    def travl(self,n):
        label=[[0 for i in range(n)] for j in range(n)]
        target=[i for i in range(1,n*n+1)]  #将[1, 2, 3, 4, 5, 6, 7, 8, 9] 排序成为#[[1, 2, 3], [8, 9, 4], [7, 6, 5]]


        print(target)
 
        def go_right(x,y):
            while True:
                if not target:
                    return label
                tmp=self.maybe(x,y)
 
                if (x>-1 and y>-1) and (x<n and y<n):
                    if label[x][y]==0:
                        label[x][y]=target.pop(0)
                        x,y=tmp[0][0],tmp[0][1]   #x,y向右移动
                    else:
                        return go_down(x+1,y-1)    #即表示该时刻(x,y+1)已经去过,重新选点(x+1,y-1)表示想下
                else:
                    go_down(x+1,y-1)             #**************************重点(躺了N次坑,由于该点表示越界或已经遍历过时情况(我们应该将此时越界的点正确调整到下一时刻应该判断的点位)
 
        def go_down(x,y):
            while True:
                if not target:
                    return label
                tmp=self.maybe(x,y)
 
                if (x>-1 and y>-1) and (x<n and y<n):
                    if label[x][y]==0:
                        label[x][y]=target.pop(0)
                        x,y=tmp[1][0],tmp[1][1]
                    else:
                        return go_left(x-1,y-1)
                else:
                    go_left(x-1,y-1)
 
        def go_left(x,y):
            while True:
                if not target:
                    return label
                tmp=self.maybe(x,y)
 
                if (x>-1 and y>-1) and (x<n and y<n):
                    if label[x][y]==0:
                        label[x][y]=target.pop(0)
                        x,y=tmp[2][0],tmp[2][1]
                    else:
                        return go_up(x-1,y+1)
                else:
                    go_up(x-1,y+1)
        def go_up(x,y):
            while True:
                if not target:
                    return label
                tmp=self.maybe(x,y)
 
                if (x>-1 and y>-1) and (x<n and y<n):
                    if label[x][y]==0:
                        label[x][y]=target.pop(0)
                        x,y=tmp[3][0],tmp[3][1]
                    else:
                        return go_right(x+1,y+1)
                else:
                    go_up(x+1,y+1)
 
        return go_right(0,0)
 
 
a=Solution().travl(3)
print(a)

 

71、二叉搜索树与双向链表

 

class Solution:
    def Convert(self, root):
        if not root:
            return
        self.tmp = []
        self.tree(root)
        for i in range(len(self.tmp)-1):
            self.tmp[i].right = self.tmp[i+1]
            self.tmp[i+1].left = self.tmp[i]

        return self.tmp[0]

    def tree(self, root):
        if not root:
            return
        self.tree(root.left)
        self.tmp.append(root)
        self.tree(root.right)

 

 

 63、和为0的最长子数组

在这里插入图片描述

思路:将问题统一转化为求SUM数组两个相同数字最远距离

class Solution:       #用空间换时间,联合使用
    def traval(self,nums):
        res=[0]*len(nums)
        res[0]=nums[0]
        for i in range(1,len(nums)):
            res[i]=res[i-1]+nums[i]

        max_tmp=0
        left_label=0
        right_label=0
        for left in range(len(res)):
            for right in range(len(res)-1,left,-1):
                if res[left]==res[right]:
                    if right-left>max_tmp:
                        left_label=left
                        right_label=right
                        max_tmp=right-left
                        break
            if res[right]==0:
                if right+1>max_tmp:
                    left_label=0
                    right_label=right
                    max_tmp=right+1
        return nums[left_label+1:right_label+1]

a=Solution().traval([7,-7,8,6,5,-5,-5,0,-6,11])
print(a)




64、从上到下打印二叉树.py

class TreeNode:
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

class MyQueue:
    def __init__(self):
        self.Queue = []

    def enqueue(self, data):
        self.Queue.append(data)

    def dequeue(self):
        return self.Queue.pop(0)

    def Print(self):
        print(self.Queue)

    def Size(self):
        return len(self.Queue)


# 不分行从上到下打印二叉树
def PrintFromTopToBottom(Node):
    if not isinstance(Node, TreeNode):
        return
    Queue = MyQueue()
    Queue.enqueue(Node)
    while Queue.Size():
        temp = Queue.dequeue()
        print(temp.data, end=' ')
        if temp.left:
            Queue.enqueue(temp.left)
        if temp.right:
            Queue.enqueue(temp.right)

# 分行从上到下打印二叉树
def PrintFromTopToBottom_2(Node):
    if not isinstance(Node, TreeNode):
        return
    Queue = MyQueue()
    toBePrinted, nextLevel = 1, 0  # toBePrinted表示本层未打印节点的数量,nextLevel表示下层要打印节点的数量
    Queue.enqueue(Node)
    while Queue.Size():
        temp = Queue.dequeue()
        print(temp.data,end=' ')
        toBePrinted -= 1
        if temp.left:
            nextLevel += 1
            Queue.enqueue(temp.left)
        if temp.right:
            nextLevel += 1
            Queue.enqueue(temp.right)
        if toBePrinted == 0:
            print()
            toBePrinted = nextLevel
            nextLevel = 0

# 之字形打印二叉树
# 需要利用两个栈来管理奇数层和偶数层
def PrintFromTopToBottom_3(Node):
    if not isinstance(Node, TreeNode):
        return
    stack1,stack2 = [Node],[]# 奇数栈从左往右打印,偶数栈从右往左打印
    stack = [stack1,stack2]
    current,next = 0,1
    while stack1 or stack2:
        temp = stack[current].pop()
        print(temp.data,end=' ')
        if current == 0:
            #在奇数层,下一层应该从右到左压入
            if temp.left:
                stack[next].append(temp.left)
            if temp.right:
                stack[next].append(temp.right)
        else:
            if temp.right:
                stack[next].append(temp.right)
            if temp.left:
                stack[next].append(temp.left)
        if not stack[current]:
            # 说明该层打印完了
            print()
            current = 1 -current
            next = 1- next


node1 = TreeNode(8)
node2 = TreeNode(6)
node3 = TreeNode(10)
node4 = TreeNode(5)
node5 = TreeNode(7)
node6 = TreeNode(9)
node7 = TreeNode(11)

node1.left, node1.right = node2, node3
node2.left, node2.right = node4, node5
node3.left, node3.right = node6, node7

#PrintFromTopToBottom(node1)
PrintFromTopToBottom_2(node1)
#PrintFromTopToBottom_3(node1)

77、序列化二叉树.

class TreeNode:
    def __init__(self,data=None,left=None,right=None):
        self.data = data
        self.left = left
        self.right = right

def Serialize(root,serializelis):
    if not root:
        serializelis.append('$')
        return
    serializelis.append(str(root.data))
    Serialize(root.left,serializelis)
    Serialize(root.right,serializelis)

def Deserialize(serializelis):
    tree,count = deserlialize(serializelis,0)
    return tree

def deserlialize(serializelis,count):
    if count >= len(serializelis) or serializelis[count]=='$':
        return None,count+1
    node = TreeNode(int(serializelis[count]))
    count += 1
    node.left,count = deserlialize(serializelis,count)
    node.right,count = deserlialize(serializelis,count)
    return node,count


node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
node5 = TreeNode(5)
node6 = TreeNode(6)

node1.left,node1.right = node2,node3
node2.left = node4
node3.left,node3.right = node5,node6

serializelis =[]
Serialize(node1,serializelis)
print(serializelis)
tree = Deserialize(serializelis)
print(tree.left.data)

 

78、二叉树中和为某一值的路径

思路: 利用递归追根节点,后用path 记录路径 1)满足条件打印,后弹出  2)不满足条件直接弹出 

           path 列表利用先序sort元素,后序弹出元素

class TreeNode:
    def __init__(self,data=None,left=None,right=None):
        self.data = data
        self.left = left
        self.right = right

def FindPath(root,n):
    path = []
    tmp = 0
    Find_Path(root,n,path,tmp)

def Find_Path(root,n,path,tmp):
    tmp += root.data
    path.append(root)
  #  print('tmp',tmp)      #10->15->19->22->22

    
    if tmp == n and not root.left and not root.right:  #找到目标且该路径到底了
        for i in path: #
            print(i.data,end=' ')
        print()

    # 如果不是叶节点,则遍历它的子节点
    if root.left:
        Find_Path(root.left,n,path,tmp)
    if root.right:
        Find_Path(root.right,n,path,tmp)

    # 在返回父节点之前,在路径上删除当前节点
    a=path.pop(-1)
   # print('111',a.data)

node1 = TreeNode(10)
node2 = TreeNode(5)
node3 = TreeNode(12)
node4 = TreeNode(4)
node5 = TreeNode(7)

node1.left,node1.right = node2,node3
node2.left,node2.right = node4,node5

FindPath(node1,22)

 

79、二叉树的最近公共祖先

 

class Solution:
    def search(self,root,node1,node2):
        if not root:
            return                     #找不到值,返回空
        if root==node1 or root==node2:
            return root                #找到值,返回值

        left=self.search(root.left,node1,node2)  #当左子树找到时,返回指针
        right=self.search(root.right,node1,node2)   #当右子树找到时,返回指针

        if left and right:
            return root             #当前节点,左子树和右子树有能找值,返回其公共节点
        if left:
            return right           #说明当前节点,左子树能找到值,右子树找不到,说明后序查找中,右子树找到值更接近主树,返回右节点
        if right:
            return left
        return None



当前置条件为二叉搜索树时:
class Solution:
    # 当树为二叉搜索树的情况
    def GetLowestNodeParent(root,node1,node2):
        if not node1 or not node2:
            return
        p = root
        # 保证p1指向值小的节点,而p2指向值大的节点
        p1, p2 = node1, node2
        if p1.data > p2.data:
            p1, p2 = node2, node1

        while p.data > p2.data or p.data < p1.data:
            if p.data > p2.data:
                p = p.left
            else:
                p = p.right
        return p

 

80、二叉树的最大路径和.

 

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def maxPathSum(self, root):
        self.maxes = -float('inf')
        
        def helper(root):

            if not root.left and not root.right:
                self.maxes = root.val if root.val > self.maxes else self.maxes
                return root.val
            
            valueLeft, valueRight = -float('inf'), -float('inf')
            
            if root.left:
                valueLeft = helper(root.left)
            
            if root.right:
                valueRight = helper(root.right)
            
            # judge left to right is max or not.
            
            self.maxes = max([root.val + valueLeft, root.val + valueRight, root.val + valueLeft + valueRight, root.val, self.maxes])
            print('root',root.val)
            print('valueLeft',valueLeft,'valueRight',valueRight)
            
            # return to parent
            return max(root.val + max(valueLeft, valueRight), root.val)
        
        helper(root)
        return self.maxes

node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
node5 = TreeNode(5)
node6 = TreeNode(6)
node7 = TreeNode(7)

node1.left,node1.right = node2,node3
node2.left,node2.right = node4,node5
node3.right = node6
node5.left = node7

a = Solution()
# print(a.TreeDepth(node1))
print(a.maxPathSum(node1))

 

79、滑窗法

class Solution(object):
    def minSubArrayLen(self, nums,s):
        l=0
        r=-1
        sum=0
        res=len(nums)+1
        while l<=len(nums)-1:
            if sum<s and r<len(nums)-1:
                r+=1
                sum+=nums[r]
            else:
                print('nums',nums[l])
                sum-=nums[l]
                print('l',l)
                l+=1
            if sum>=s:
                res=min(res,r-l+1)
        if res==len(nums)+1:
            return 0
        return res


nums=[6,5,3,1,9,12,4,2]
print(Solution().minSubArrayLen(nums,20))

 

80、

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值