123
返回列表 发新帖
楼主: Wangjingru_1995
跳转到指定楼层
上一主题 下一主题
收起左侧

刷题打卡

🔗
 楼主| Wangjingru_1995 2019-3-15 11:14:14 | 只看该作者
全局:
Day 15:

Q1. Map Sum Pairs【Medium】
题目理解:数据结构设计题,要求设计MapSum,并实现insert和sum两个自定义功能
                1)初始化:先对给定Mapsum进行初始化(一个空的set)
                2)insert:将给定的key,value对插入Mapsum,若key已存在则进行覆盖
                3)sum:给定一个prefix,要求输出一个int表示所有以prefix开头的key对应的value之和

解决方法:基本是比对答案自行领悟

注:1)initialize:需要自定义一个空集且要注意语法,因为属于内部数据,因此需要在前面加self前缀,例如:self.map = {}
      2)insert:因为若存在就覆盖,所以直接进行赋值即可,简单直接,和1)类似,对内部数据操作同样要记得加self。self.map[key] = value
      3)sum:这里我学到了一个用法叫做key.startswith(prefix),这样即可方便的指代所有prefix开头的key,只需自己加一个循环即可。
ans = sum(val for key, val in self.map.items() if key.startswith(prefix))
#这里也可以拆开写成for循环,这样写更加简洁,但是可读性稍显降低
return ans

Q2. Maximal Square 【Medium】
题目理解:1)输入:2D矩阵matrix,仅包含0或1
                2)输出:整数,表示矩阵中所有元素均为1的最大正方形的面积。

解决方法: 1)递推+检验。自定义一个矩阵dp,size是(m+1)*(n+1),就是比原矩阵matrix多一行一列(为了简化边界条件的描述)。每个位置dp[i+1][j+1]表示原矩阵中从左上角开始到第[I, j]个位置的矩形中所有元素和。这样我们在计算任意一个指定矩阵的元素和时就可以用大减小的方式计算。第一次双重循环用递推的方式填充dp。之后对我们所要找的正方形进行检验。具体操作是在进行双重循环指定右下角边界的同时,加入一个循环用于判断dp[i][j]左上角能够包含的所有正方形是否满足条件并更新最大值,循环全部结束后,输出最大值即可。由于原矩阵中只有0,1因此当所有元素和为平方时满足条件,具体实现如下(python):

class Solution(object):
    def maximalSquare(self, matrix):
        m = len(matrix)
        if m == 0:
            return 0
        n = len(matrix[0])
        dp = [[0]*(n+1) for row in range(0, m+1)]
        
        maxk = 0
        for i in range(1, m+1):
            for j in range(1, n+1):
                if int(matrix[i-1][j-1]) == 1:
                    dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
                    maxk = max(maxk, dp[i][j])
        ans = maxk*maxk
        return ans

注:这个方法虽然时间上较2)更为复杂,但是方法通用性强,在多种变形下均能适用。例如下一题中计算某个范围内的所有元素和的最大值等。

                2)递推。与1)不同点在于这种方法下的dp用于逐步更新以每个点为右下角的最大正方形,最后直接返回dp中所有元素的最大值。这个方法对于这道题而言十分巧妙,利用了非0即1的性质,算是一个思想更复杂一点的动态规划,将递推关系建立在每个小的2*2的矩阵中:右下角的值 = min(左下,左上,正上) + 1。当然如果右下角元素为0,那么以右下为定点的正方形并不满足条件,因此直接置0即可。看起来比较费解,但是自己动手画一下就能很容易发现了。具体实现如下(python):

class Solution(object):
    def maximalSquare(self, matrix):
        m = len(matrix)
        if m == 0:
            return 0
        n = len(matrix[0])
        dp = [[0]*(n+1) for row in range(0, m+1)]
        
        maxk = 0
        for i in range(1, m+1):
            for j in range(1, n+1):
                if int(matrix[i-1][j-1]) == 1:
                    dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
                    maxk = max(maxk, dp[i][j])
        ans = maxk*maxk
        return ans

Q3. Range Sum Query 2D - Immutable 【Medium】
题目理解:详见leetcode 304.
解决方法:这道题跟上一题第一种解法几乎完全相同,所以思路就不赘述了。唯一的不同就是这是个数据结构设计题,功能一样,只是要进行一些交互。具体实现如下(python):

class NumMatrix(object):

    def __init__(self, matrix):        
        m = len(matrix)
        if m == 0:
            return
        n = len(matrix[0])
        self.dp = [[0]*(n+1) for row in range(0, m+1)]
        for i in range(1, m+1):
            for j in range(1, n+1):
                if i == 1 and j == 1:
                    self.dp[i][j] = matrix[i-1][j-1]
                else:
                    self.dp[i][j] = matrix[i-1][j-1] + self.dp[i-1][j] + self.dp[i][j-1] - self.dp[i-1][j-1]

    def sumRegion(self, row1, col1, row2, col2):        
        ans = self.dp[row2+1][col2+1] - self.dp[row1][col2+1] - self.dp[row2+1][col1] + self.dp[row1][col1]
        return ans

Q4. Number of Islands 【Medium】
题目理解:1)输入:0、1矩阵grid,1表示陆地,0表示水,上下左右相邻记为相连
                2)输出:整数,表示grid中岛屿的数量

解决方法:dfs 。对grid进行遍历,每次遇到岛屿都用dfs遍历所有相邻岛屿,并置0,同时岛屿数量加1。在dfs自定义函数中递归调用遍历上下左右节点即可。且这道题不需要回溯。

class Solution(object):
    def numIslands(self, grid):      
        m = len(grid)
        if m == 0:
            return 0
        n = len(grid[0])
        ans = 0
        for i in range(0, m):
            for j in range(0, n):
                ans += int(grid[i][j])
                self.dfs(grid, i, j, m, n)
        return ans
        
    def dfs(self, grid, i, j, m, n):
        if i < 0 or j < 0 or i > m-1 or j > n-1 or grid[i][j] == '0':
            return
        grid[i][j] = '0'
        self.dfs(grid, i+1, j, m, n)
        self.dfs(grid, i-1, j, m, n)
        self.dfs(grid, i, j+1, m, n)
        self.dfs(grid, i, j-1, m, n)

Q5. Friend Circles【Medium】
题目理解:1)输入:0、1矩阵M。M[i][j] = 1表示第i、j个小朋友互为好友,每个小朋友的好友圈共享,M[i][i]总是为1。M为n*n的正方形矩阵
                2)输出:整数,表示整个班级中总共有几个互不联通的朋友圈

解决方法:dfs。这道题和上一题较为类似,唯一的不同在于好友圈共享。这里我们利用一个visited数组(size为n,初始化为0)来表示每个小朋友是否已经被归类。具体实现如下:

class Solution(object):
def findCircleNum(self, M):
    n = len(M)
        if n == 0:
            return 0
        visited = [0] * n
        ans = 0
        for i in range(0, n):
            if visited[i]:
                continue
            self.dfs(M, i, n, visited)
            ans += 1
        
        return ans
   
    def dfs(self, M, i, n, visited):
        if visited[i]:
            return
        visited[i] = 1
        for j in range(0, n):
            if not visited[j] and M[i][j] == 1:
                self.dfs(M, j, n, visited)
               

注:一转就这么到了加州,没想到才短短两天就基本适应了这边的生活。来到这个天气和环境都十分美丽的城市,仿佛离目标更近了,希望未来一切顺利,努力并持续期待着。 加油!💪💪💪

评分

参与人数 1大米 +5 收起 理由
amcw7777 + 5 加油!

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-3-28 07:30:22 | 只看该作者
全局:
Day 16:

Q1. Distribute Coins in Binary Tree 【Medium】
题目理解:1)输入:二叉树根节点root
                2)输出:整数,表示对原二叉树进行(最少)操作的次数使其满足题目要求
                3)原二叉树上的每个节点的value表示该节点上的金币数,整棵二叉树一共有n个节点,所有节点的value和为n。要求所有操作结束时,每个节点上有且仅有一枚金币
                4)操作方式:每次可以将某节点的金币挪到其相邻节点(夫或子节点均可,但两节点之间必须有支直接相连),每次操作表示从一个节点向一个相邻节点挪动一枚金币,同一分支上挪动两次表示两步操作

解决方法:递归。基本上所有跟树相关的题目都可以用dfs来解决,这道题也不例外。我们借助dfs(root)函数来进行递归操作,每个根节点用于平衡左右子树的总金币数。dfs函数的返回值为以root为根节点的子树需要跟外界进行操作的次数,简单来讲就是:如果现在root树一共x个节点,y枚金币,那么dfs(root)会返回y-x,相当于这棵树的balance值。在整个解题过程中我们设定一个全局变量self.ans用来记录最终结果,注意ans和balance的不同在于,balance可以为负,但ans需要记录所有balance的绝对值之和。具体实现如下(python),过程非常简洁:

class Solution(object):
    def distributeCoins(self, root):
        self.ans = 0
        self.dfs(root)
        return self.ans
   
    def dfs(self, root):
        if not root:
            return 0
        l = self.dfs(root.left)
        r = self.dfs(root.right)
        self.ans += abs(l) + abs(r)
        return l + r + root.val - 1

Q2. Numbers With Same Consecutive Differences 【Medium】
题目理解:1)输入:整数N,整数K。其中N表示返回结果中每个非负整数的长度,K表示返回结果的每个数中,任意两个相邻位置的数值之差的绝对值
                2)输出:所有满足条件的非负整数的列表
                3)1<= N <= 9,         0<= K<=9
                4)当N>1时,结果不能以0开头

解决方法: 这道题目可以用bfs和dfs两种方法来解决,但是整体思路类似,首先对于特殊情况N=1,无论K是多少都会返回[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。对于其他情况,当长度小于N时,根据K和当前数字curr的最后一位进行操作来构造下一位并更新curr即可。除了N=1外,其他情况下每次都只能遍历1~9这9个数字。

                1)dfs。自定义dfs(N, K, curr, ans)函数用于构造长度为N的数,递归终止条件为N = 0,此时将curr插入ans中。其余情况下,分别判断curr%10 + K或者curr%10 – K是否会越界,若不越界进一步递归即可。具体实现如下(python):

class Solution(object):
    def numsSameConsecDiff(self, N, K):
        ans = []
        if N == 1:
            ans.append(0)
        for i in range(1, 10):
            self.dfs(N-1, K, i, ans)
        return ans
   
    def dfs(self, N, K, curr, ans):
        if N == 0:
            ans.append(curr)
            return
        r = curr%10
        if r + K <= 9:
            self.dfs(N-1, K, curr*10 + r + K, ans)
        if r - K >= 0 and K!=0:
            self.dfs(N-1, K, curr*10 + r - K, ans)
        
                2)bfs。和dsf类似,只不过在数字长度小于N时每次逐层更新,过程中需要利用一个额外的空间来记录每一层的值。具体实现如下(python):

class Solution(object):
    def numsSameConsecDiff(self, N, K):
        q = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        if N == 1:
            q.insert(0, 0)
        while N > 1:
            size = len(q)
            while size > 0:
                curr = q[0]
                q.pop(0)
                r = curr%10
                if r+K <= 9:
                    q.append(curr*10 + r + K)
                if r-K >= 0 and K != 0:
                    q.append(curr*10 + r - K)
                size -= 1
            N -= 1
        return q

Q3. Subsets 【Medium】
题目理解:1)输入:list of distinct integers,nums
                2)输出:list of list,表示nums的所有subsets

解决方法:1)dfs。利用自定义函数dfs(nums, n, s, curr)来递归求解nums长度为n且起始坐标为s的subsets,curr用于记录当前操作的list,递归终止条件为curr的长度等于n。需要回溯。具体实现如下(python):

class Solution(object):
    def subsets(self, nums):
        self.ans = []
        for i in range(0, len(nums)+1):
            curr = []
            self.dfs(nums, i, 0, curr)
        return self.ans
        
    def dfs(self, nums, n, s, curr):
        if len(curr) == n:
            self.ans.append(curr[:])
            return
        for i in range(s, len(nums)):
            curr.append(nums[i])
            self.dfs(nums, n, i+1, curr)
            curr.pop()

                2)brute force直接构造subsets也能解决,具体实现如下:

class Solution(object):
    def subsets(self, nums):
        if len(nums) == 0: return [[]]
        ans = []
        ans.append([])

        for i in range (0,len(nums)):
            for j in range(0,i):
                aa = []
                aa.append(nums[j:(i-1)])
                ans.append(aa)
        return ans

Q4. Shortest Bridge 【Medium】
题目理解:1)输入:0、1矩阵A,1表示陆地,0表示水,上下左右相邻记为相连,整个矩阵中一共有2个小岛
                2)输出:整数,表示 两个岛屿之间至少通过几步可以连接在一起
                3)题目已知共有两个小岛,答案至少为1

解决方法:dfs + bfs。先对A进行遍历,找到第一个岛屿,并通过dfs将该岛屿的所有元素值赋值为2。接下来利用bfs将这个每处都为2的岛屿逐层扩展,bfs每扩展一层,step加1,直到扩展到另一个岛屿(值为1),返回step即可。具体实现如下:

class Solution(object):
def shortestBridge(self, A):
    m = len(A)
        if m == 0:
            return -1
        n = len(A[0])
        found = False
        visited = []
    #先找到第一个岛屿
        for i in range(0, m):
            for j in range(0, n):
                if not found and A[i][j]:
                    self.dfs(A, i, j, visited)
                    found = True
                    break
     #用bfs逐步扩展第一个岛屿      
        step = 0
        dirs = [0, 1, 0, -1, 0]

        while visited:
            size = len(visited)
            while size:
                x = visited[0][0]
                y = visited[0][1]
                visited.pop(0)
                size -= 1
                for i in range(0, 4):
                    tx = x + dirs[i]
                    ty = y + dirs[i+1]
                    if tx<0 or tx>m-1 or ty<0 or ty>n-1 or A[tx][ty] == 2:
                        continue
                    if A[tx][ty] == 1:
                        return step
                    A[tx][ty] = 2
                    visited.append((tx, ty))
            step += 1
        return -1

    #用dfs标记第一个岛屿为2,与另一个岛屿区分开来
    def dfs(self, A, x, y, visited):
        m = len(A)
        n = len(A[0])
        if x<0 or x >m-1 or y<0 or y>n-1 or A[x][y] != 1:
            return
        A[x][y] = 2
        visited.append((x, y))
        self.dfs(A, x-1, y, visited)
        self.dfs(A, x+1, y, visited)
        self.dfs(A, x, y-1, visited)
        self.dfs(A, x, y+1, visited)

Q5. Redundant Connection 【Medium】
题目理解:1)输入:list[list[int]],edges表示一个无向图中节点之间的连线
                2)输出:list[int],为edges里面的一条edge,表示原图将edge删去后可以形成一个二叉树,且若有多个选择,edge为位置最靠后的一条。
                3)每个edge[u, v]都满足u<v

解决方法:union find。听说这是一道很经典的题,作为第一次接触这类题的我,反正我在理解union find的解题过程的时候用了挺长时间的。方法理解倒是还好,就是将所有连在一起的节点统一在一个set中,定义一个parent作为整个节点集的代表,因为题目要求删去满足条件且位置最靠后的edge,因此parent尽量保留最小元素,且当两个set(一大一小)进行融合时,保留元素较多的set并依旧取最小元素为parent,具体实现过程如下:

class Solution(object):
    def findRedundantConnection(self, edges):
        n = len(edges)
        p = [0] * (n+1)
        s = [1] * (n+1)
        
        for u,v in edges:
            if p[u] == 0:
                p[u] = u
            if p[v] == 0:
                p[v] = v
            pu = self.find(u, p)
            pv = self.find(v, p)
            if pu == pv:
                return [u, v]
            
            if s[pv] > s[pu]:
                temp = v
                v = u
                u = temp
            p[pv] = pu
            s[pu] += s[pv]
        return []
   
    def find(self, u, p):
        while p[u] != u:
            p[u] = p[p[u]]
            u = p[u]
        return u

评分

参与人数 1大米 +3 收起 理由
amcw7777 + 3 加油!

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-3-28 07:32:21 | 只看该作者
全局:
Day 16:

Q1. Distribute Coins in Binary Tree 【Medium】
题目理解:1)输入:二叉树根节点root
                2)输出:整数,表示对原二叉树进行(最少)操作的次数使其满足题目要求
                3)原二叉树上的每个节点的value表示该节点上的金币数,整棵二叉树一共有n个节点,所有节点的value和为n。要求所有操作结束时,每个节点上有且仅有一枚金币
                4)操作方式:每次可以将某节点的金币挪到其相邻节点(夫或子节点均可,但两节点之间必须有支直接相连),每次操作表示从一个节点向一个相邻节点挪动一枚金币,同一分支上挪动两次表示两步操作

解决方法:递归。基本上所有跟树相关的题目都可以用dfs来解决,这道题也不例外。我们借助dfs(root)函数来进行递归操作,每个根节点用于平衡左右子树的总金币数。dfs函数的返回值为以root为根节点的子树需要跟外界进行操作的次数,简单来讲就是:如果现在root树一共x个节点,y枚金币,那么dfs(root)会返回y-x,相当于这棵树的balance值。在整个解题过程中我们设定一个全局变量self.ans用来记录最终结果,注意ans和balance的不同在于,balance可以为负,但ans需要记录所有balance的绝对值之和。具体实现如下(python),过程非常简洁:

class Solution(object):
    def distributeCoins(self, root):
        self.ans = 0
        self.dfs(root)
        return self.ans
   
    def dfs(self, root):
        if not root:
            return 0
        l = self.dfs(root.left)
        r = self.dfs(root.right)
        self.ans += abs(l) + abs(r)
        return l + r + root.val - 1

Q2. Numbers With Same Consecutive Differences 【Medium】
题目理解:1)输入:整数N,整数K。其中N表示返回结果中每个非负整数的长度,K表示返回结果的每个数中,任意两个相邻位置的数值之差的绝对值
                2)输出:所有满足条件的非负整数的列表
                3)1<= N <= 9,         0<= K<=9
                4)当N>1时,结果不能以0开头

解决方法: 这道题目可以用bfs和dfs两种方法来解决,但是整体思路类似,首先对于特殊情况N=1,无论K是多少都会返回[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。对于其他情况,当长度小于N时,根据K和当前数字curr的最后一位进行操作来构造下一位并更新curr即可。除了N=1外,其他情况下每次都只能遍历1~9这9个数字。

                1)dfs。自定义dfs(N, K, curr, ans)函数用于构造长度为N的数,递归终止条件为N = 0,此时将curr插入ans中。其余情况下,分别判断curr%10 + K或者curr%10 – K是否会越界,若不越界进一步递归即可。具体实现如下(python):

class Solution(object):
    def numsSameConsecDiff(self, N, K):
        ans = []
        if N == 1:
            ans.append(0)
        for i in range(1, 10):
            self.dfs(N-1, K, i, ans)
        return ans
   
    def dfs(self, N, K, curr, ans):
        if N == 0:
            ans.append(curr)
            return
        r = curr%10
        if r + K <= 9:
            self.dfs(N-1, K, curr*10 + r + K, ans)
        if r - K >= 0 and K!=0:
            self.dfs(N-1, K, curr*10 + r - K, ans)
        
                2)bfs。和dsf类似,只不过在数字长度小于N时每次逐层更新,过程中需要利用一个额外的空间来记录每一层的值。具体实现如下(python):

class Solution(object):
    def numsSameConsecDiff(self, N, K):
        q = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        if N == 1:
            q.insert(0, 0)
        while N > 1:
            size = len(q)
            while size > 0:
                curr = q[0]
                q.pop(0)
                r = curr%10
                if r+K <= 9:
                    q.append(curr*10 + r + K)
                if r-K >= 0 and K != 0:
                    q.append(curr*10 + r - K)
                size -= 1
            N -= 1
        return q

Q3. Subsets 【Medium】
题目理解:1)输入:list of distinct integers,nums
                2)输出:list of list,表示nums的所有subsets

解决方法:1)dfs。利用自定义函数dfs(nums, n, s, curr)来递归求解nums长度为n且起始坐标为s的subsets,curr用于记录当前操作的list,递归终止条件为curr的长度等于n。需要回溯。具体实现如下(python):

class Solution(object):
    def subsets(self, nums):
        self.ans = []
        for i in range(0, len(nums)+1):
            curr = []
            self.dfs(nums, i, 0, curr)
        return self.ans
        
    def dfs(self, nums, n, s, curr):
        if len(curr) == n:
            self.ans.append(curr[:])
            return
        for i in range(s, len(nums)):
            curr.append(nums[i])
            self.dfs(nums, n, i+1, curr)
            curr.pop()

                2)brute force直接构造subsets也能解决,具体实现如下:

class Solution(object):
    def subsets(self, nums):
        if len(nums) == 0: return [[]]
        ans = []
        ans.append([])

        for i in range (0,len(nums)):
            for j in range(0,i):
                aa = []
                aa.append(nums[j:(i-1)])
                ans.append(aa)
        return ans

Q4. Shortest Bridge 【Medium】
题目理解:1)输入:0、1矩阵A,1表示陆地,0表示水,上下左右相邻记为相连,整个矩阵中一共有2个小岛
                2)输出:整数,表示 两个岛屿之间至少通过几步可以连接在一起
                3)题目已知共有两个小岛,答案至少为1

解决方法:dfs + bfs。先对A进行遍历,找到第一个岛屿,并通过dfs将该岛屿的所有元素值赋值为2。接下来利用bfs将这个每处都为2的岛屿逐层扩展,bfs每扩展一层,step加1,直到扩展到另一个岛屿(值为1),返回step即可。具体实现如下:

class Solution(object):
def shortestBridge(self, A):
    m = len(A)
        if m == 0:
            return -1
        n = len(A[0])
        found = False
        visited = []
    #先找到第一个岛屿
        for i in range(0, m):
            for j in range(0, n):
                if not found and A[i][j]:
                    self.dfs(A, i, j, visited)
                    found = True
                    break
     #用bfs逐步扩展第一个岛屿      
        step = 0
        dirs = [0, 1, 0, -1, 0]

        while visited:
            size = len(visited)
            while size:
                x = visited[0][0]
                y = visited[0][1]
                visited.pop(0)
                size -= 1
                for i in range(0, 4):
                    tx = x + dirs[i]
                    ty = y + dirs[i+1]
                    if tx<0 or tx>m-1 or ty<0 or ty>n-1 or A[tx][ty] == 2:
                        continue
                    if A[tx][ty] == 1:
                        return step
                    A[tx][ty] = 2
                    visited.append((tx, ty))
            step += 1
        return -1

    #用dfs标记第一个岛屿为2,与另一个岛屿区分开来
    def dfs(self, A, x, y, visited):
        m = len(A)
        n = len(A[0])
        if x<0 or x >m-1 or y<0 or y>n-1 or A[x][y] != 1:
            return
        A[x][y] = 2
        visited.append((x, y))
        self.dfs(A, x-1, y, visited)
        self.dfs(A, x+1, y, visited)
        self.dfs(A, x, y-1, visited)
        self.dfs(A, x, y+1, visited)

Q5. Redundant Connection 【Medium】
题目理解:1)输入:list[list[int]],edges表示一个无向图中节点之间的连线
                2)输出:list[int],为edges里面的一条edge,表示原图将edge删去后可以形成一个二叉树,且若有多个选择,edge为位置最靠后的一条。
                3)每个edge[u, v]都满足u<v

解决方法:union find。听说这是一道很经典的题,作为第一次接触这类题的我,反正我在理解union find的解题过程的时候用了挺长时间的。方法理解倒是还好,就是将所有连在一起的节点统一在一个set中,定义一个parent作为整个节点集的代表,因为题目要求删去满足条件且位置最靠后的edge,因此parent尽量保留最小元素,且当两个set(一大一小)进行融合时,保留元素较多的set并依旧取最小元素为parent,具体实现过程如下:

class Solution(object):
    def findRedundantConnection(self, edges):
        n = len(edges)
        p = [0] * (n+1)
        s = [1] * (n+1)
        
        for u,v in edges:
            if p[u] == 0:
                p[u] = u
            if p[v] == 0:
                p[v] = v
            pu = self.find(u, p)
            pv = self.find(v, p)
            if pu == pv:
                return [u, v]
            
            if s[pv] > s[pu]:
                temp = v
                v = u
                u = temp
            p[pv] = pu
            s[pu] += s[pv]
        return []
   
    def find(self, u, p):
        while p[u] != u:
            p[u] = p[p[u]]
            u = p[u]
        return u

评分

参与人数 1大米 +3 收起 理由
amcw7777 + 3 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-3-28 07:40:37 | 只看该作者
全局:
Day 16:

Q1. Distribute Coins in Binary Tree 【Medium】
题目理解:1)输入:二叉树根节点root
                2)输出:整数,表示对原二叉树进行(最少)操作的次数使其满足题目要求
                3)原二叉树上的每个节点的value表示该节点上的金币数,整棵二叉树一共有n个节点,所有节点的value和为n。要求所有操作结束时,每个节点上有且仅有一枚金币
                4)操作方式:每次可以将某节点的金币挪到其相邻节点(夫或子节点均可,但两节点之间必须有支直接相连),每次操作表示从一个节点向一个相邻节点挪动一枚金币,同一分支上挪动两次表示两步操作

解决方法:递归。基本上所有跟树相关的题目都可以用dfs来解决,这道题也不例外。我们借助dfs(root)函数来进行递归操作,每个根节点用于平衡左右子树的总金币数。dfs函数的返回值为以root为根节点的子树需要跟外界进行操作的次数,简单来讲就是:如果现在root树一共x个节点,y枚金币,那么dfs(root)会返回y-x,相当于这棵树的balance值。在整个解题过程中我们设定一个全局变量self.ans用来记录最终结果,注意ans和balance的不同在于,balance可以为负,但ans需要记录所有balance的绝对值之和。具体实现如下(python),过程非常简洁:

class Solution(object):
    def distributeCoins(self, root):
        self.ans = 0
        self.dfs(root)
        return self.ans
   
    def dfs(self, root):
        if not root:
            return 0
        l = self.dfs(root.left)
        r = self.dfs(root.right)
        self.ans += abs(l) + abs(r)
        return l + r + root.val - 1

Q2. Numbers With Same Consecutive Differences 【Medium】
题目理解:1)输入:整数N,整数K。其中N表示返回结果中每个非负整数的长度,K表示返回结果的每个数中,任意两个相邻位置的数值之差的绝对值
                2)输出:所有满足条件的非负整数的列表
                3)1<= N <= 9,         0<= K<=9
                4)当N>1时,结果不能以0开头

解决方法: 这道题目可以用bfs和dfs两种方法来解决,但是整体思路类似,首先对于特殊情况N=1,无论K是多少都会返回[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。对于其他情况,当长度小于N时,根据K和当前数字curr的最后一位进行操作来构造下一位并更新curr即可。除了N=1外,其他情况下每次都只能遍历1~9这9个数字。

                1)dfs。自定义dfs(N, K, curr, ans)函数用于构造长度为N的数,递归终止条件为N = 0,此时将curr插入ans中。其余情况下,分别判断curr%10 + K或者curr%10 – K是否会越界,若不越界进一步递归即可。具体实现如下(python):

class Solution(object):
    def numsSameConsecDiff(self, N, K):
        ans = []
        if N == 1:
            ans.append(0)
        for i in range(1, 10):
            self.dfs(N-1, K, i, ans)
        return ans
   
    def dfs(self, N, K, curr, ans):
        if N == 0:
            ans.append(curr)
            return
        r = curr%10
        if r + K <= 9:
            self.dfs(N-1, K, curr*10 + r + K, ans)
        if r - K >= 0 and K!=0:
            self.dfs(N-1, K, curr*10 + r - K, ans)
        
                2)bfs。和dsf类似,只不过在数字长度小于N时每次逐层更新,过程中需要利用一个额外的空间来记录每一层的值。具体实现如下(python):

class Solution(object):
    def numsSameConsecDiff(self, N, K):
        q = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        if N == 1:
            q.insert(0, 0)
        while N > 1:
            size = len(q)
            while size > 0:
                curr = q[0]
                q.pop(0)
                r = curr%10
                if r+K <= 9:
                    q.append(curr*10 + r + K)
                if r-K >= 0 and K != 0:
                    q.append(curr*10 + r - K)
                size -= 1
            N -= 1
        return q

Q3. Subsets 【Medium】
题目理解:1)输入:list of distinct integers,nums
                2)输出:list of list,表示nums的所有subsets

解决方法:1)dfs。利用自定义函数dfs(nums, n, s, curr)来递归求解nums长度为n且起始坐标为s的subsets,curr用于记录当前操作的list,递归终止条件为curr的长度等于n。需要回溯。具体实现如下(python):

class Solution(object):
    def subsets(self, nums):
        self.ans = []
        for i in range(0, len(nums)+1):
            curr = []
            self.dfs(nums, i, 0, curr)
        return self.ans
        
    def dfs(self, nums, n, s, curr):
        if len(curr) == n:
            self.ans.append(curr[:])
            return
        for i in range(s, len(nums)):
            curr.append(nums[i])
            self.dfs(nums, n, i+1, curr)
            curr.pop()

                2)brute force直接构造subsets也能解决,具体实现如下:

class Solution(object):
    def subsets(self, nums):
        if len(nums) == 0: return [[]]
        ans = []
        ans.append([])

        for i in range (0,len(nums)):
            for j in range(0,i):
                aa = []
                aa.append(nums[j:(i-1)])
                ans.append(aa)
        return ans

Q4. Shortest Bridge 【Medium】
题目理解:1)输入:0、1矩阵A,1表示陆地,0表示水,上下左右相邻记为相连,整个矩阵中一共有2个小岛
                2)输出:整数,表示 两个岛屿之间至少通过几步可以连接在一起
                3)题目已知共有两个小岛,答案至少为1

解决方法:dfs + bfs。先对A进行遍历,找到第一个岛屿,并通过dfs将该岛屿的所有元素值赋值为2。接下来利用bfs将这个每处都为2的岛屿逐层扩展,bfs每扩展一层,step加1,直到扩展到另一个岛屿(值为1),返回step即可。具体实现如下:

class Solution(object):
def shortestBridge(self, A):
    m = len(A)
        if m == 0:
            return -1
        n = len(A[0])
        found = False
        visited = []
    #先找到第一个岛屿
        for i in range(0, m):
            for j in range(0, n):
                if not found and A[i][j]:
                    self.dfs(A, i, j, visited)
                    found = True
                    break
     #用bfs逐步扩展第一个岛屿      
        step = 0
        dirs = [0, 1, 0, -1, 0]

        while visited:
            size = len(visited)
            while size:
                x = visited[0][0]
                y = visited[0][1]
                visited.pop(0)
                size -= 1
                for i in range(0, 4):
                    tx = x + dirs[i]
                    ty = y + dirs[i+1]
                    if tx<0 or tx>m-1 or ty<0 or ty>n-1 or A[tx][ty] == 2:
                        continue
                    if A[tx][ty] == 1:
                        return step
                    A[tx][ty] = 2
                    visited.append((tx, ty))
            step += 1
        return -1

    #用dfs标记第一个岛屿为2,与另一个岛屿区分开来
    def dfs(self, A, x, y, visited):
        m = len(A)
        n = len(A[0])
        if x<0 or x >m-1 or y<0 or y>n-1 or A[x][y] != 1:
            return
        A[x][y] = 2
        visited.append((x, y))
        self.dfs(A, x-1, y, visited)
        self.dfs(A, x+1, y, visited)
        self.dfs(A, x, y-1, visited)
        self.dfs(A, x, y+1, visited)

Q5. Redundant Connection 【Medium】
题目理解:1)输入:list[list[int]],edges表示一个无向图中节点之间的连线
                2)输出:list[int],为edges里面的一条edge,表示原图将edge删去后可以形成一个二叉树,且若有多个选择,edge为位置最靠后的一条。
                3)每个edge[u, v]都满足u<v

解决方法:union find。听说这是一道很经典的题,作为第一次接触这类题的我,反正我在理解union find的解题过程的时候用了挺长时间的。方法理解倒是还好,就是将所有连在一起的节点统一在一个set中,定义一个parent作为整个节点集的代表,因为题目要求删去满足条件且位置最靠后的edge,因此parent尽量保留最小元素,且当两个set(一大一小)进行融合时,保留元素较多的set并依旧取最小元素为parent,具体实现过程如下:

class Solution(object):
    def findRedundantConnection(self, edges):
        n = len(edges)
        p = [0] * (n+1)
        s = [1] * (n+1)
        
        for u,v in edges:
            if p[u] == 0:
                p[u] = u
            if p[v] == 0:
                p[v] = v
            pu = self.find(u, p)
            pv = self.find(v, p)
            if pu == pv:
                return [u, v]
            
            if s[pv] > s[pu]:
                temp = v
                v = u
                u = temp
            p[pv] = pu
            s[pu] += s[pv]
        return []
   
    def find(self, u, p):
        while p[u] != u:
            p[u] = p[p[u]]
            u = p[u]
        return u

评分

参与人数 1大米 +3 收起 理由
amcw7777 + 3 加油!

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-3-29 11:35:14 | 只看该作者
全局:
Day 17:

Q1. Valid Parenthesis String 【Medium】
题目理解:1)输入:字符串s,里面仅包含“(”、“)”、“*”
                2)输出:bool结果,表示原字符串s中的左右括号可否相互抵消
                3)规则:每个“*”可以作为“(”或者“)”使用,要求每个“(”都必须有相应的“)”匹配,且“(”必须出现在“)”之前。注意,当s为空字符串时也算满足条件,应返回True

解决方法:直接遍历计数。因为原字符串s中仅有3种字符,我们最终只关注是否所有“(”均可以被完全匹配,且“*”的定义有两种可能性,这里我们只需要记录所有需要匹配的“(”数量的上下限,其中下限表示必须匹配的“(”,也就是原字符串s中“(”的数量,而上限则为“(”+“*”的数量和,这个上线是为了防止任何substring中“)”出现在“(”之前。而且使用上下限只是为了限定能否满足要求,并没有对每个“*”进行一一赋值(因为题目只要求输出bool结果,并没有要求我们进行一一匹配)。在进行循环的过程中,我们需要每次都判断上限是否为负,且下限为负时及时清零。最终循环结束时,只需要判断下限是否为零即可。具体实现如下(python):

class Solution(object):
    def checkValidString(self, s):
        Min = 0
        Max = 0
        n = len(s)
        if n == 0:
            return True
        for i in range(0, n):
            if s[i] == "(":
                Min += 1
            else:
                Min -= 1
            if s[i] != ")":
                Max += 1
            else:
                Max -= 1
            if Min < 0:
                Min = 0
            if Max < 0:
                return False
        if Min == 0:
return True

Q2. Knight Probability in Chessboard 【Medium】
题目理解:1)输入:整数N,整数K,整数r,整数c。其中N表示棋盘的尺寸为N*N,K表示需要行走的步数,r、c分别表示棋盘上的起始行、列(作为起始位置)
                2)输出:概率值,表示从[r, c]开始行走K步后,knight依然在棋盘上的概率
                3)knight行走规则:“日”字形前进,即每次在棋盘上沿1:2的方向行走

解决方法: 递推计数,利用了动态规划。根据题目描述,knight从每个位置开始都有8种行走方式,下面代码里面directions表示的就是knight的8种行走方向。我们从第1步开始分别记录走到棋盘上每一个格子[i, j]的行走方式有几种,每多一步走过的位置,不断累加结果,直到最后走完K步。当走完K步之后,将棋盘上每个位置上对应的值求和total,就是最后knight留在棋盘上的结果数量,而因为每一次knight都有8种走法,所以总共有T = 8^N种情况,最后返回total/T即可。 具体实现如下(python):

class Solution(object):
    def knightProbability(self, N, K, r, c):
        directions = [[2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1,-2]]
        dp0 = [[0.0]*N for row in range(0, N)]
        dp0[r][c] = 1.0
        for k in range(0, K):
            dp1 = [[0.0]*N for row in range(0, N)]
            for i in range(0, N):
                for j in range(0, N):
               
                    for d in range(0, 8):
                        x = i + directions[d][0]
                        y = j + directions[d][1]
                        if x<0 or y<0 or x>=N or y>=N:
                            continue
                        dp1[x][y] += dp0[i][j]
            temp = dp0
            dp0 = dp1
            dp1 = temp
        total = 0.0
        for i in range(0, N):
            for j in range(0, N):
                total += dp0[i][j]
        T = 8**K
        return total/T

Q3. Combination Sum 【Medium】
题目理解:1)输入:list[int],candidates和整数target,其中candidates中没有重复元素,但是每个元素可以重复使用
                2)输出:list[list[int]],表示candidates中所有和为target的整数列表

解决方法:dfs。首先对原数组进行排序,利用自定义函数dfs(self, candidates, target, s, curr, ans)来递归求解candidates中以s为起始位置的情况,curr用于记录当前操作的list,递归终止条件为target = 0。需要回溯。具体实现如下(python):

class Solution(object):
    def combinationSum(self, candidates, target):        
        candidates.sort()
        curr = []
        ans = []
        self.dfs(candidates, target, 0, curr, ans)
        return ans
   
    def dfs(self, candidates, target, s, curr, ans):
        if target == 0:
            ans.append(curr[:])
            return
        n = len(candidates)
        for i in range(s, n):     
            if candidates[i] > target:
                break
            curr.append(candidates[i])
            self.dfs(candidates, target - candidates[i], i, curr, ans)
            curr.pop()

【优化】对于输出的结果,我们可以按照每个list的长度进行排序输出,除了对之前结果按照长度排序之外,我们也可以在求解时直接进行一些操作,几乎为同样的实现方式,只不过在dfs中需要多加一些变量来记录递归深度。具体实现如下:

class Solution(object):
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        candidates.sort()
        curr = []
        ans = []
        for i in range(1, target/candidates[0]+1):            
            self.dfs(candidates, target, 0, 0, i, curr, ans)
        return ans
   
    def dfs(self, candidates, target, s, d, e, curr, ans):
        if d == e:
            if target == 0:
                ans.append(curr[:])
            return
        
        n = len(candidates)
        for i in range(s, n):     
            if candidates[i] > target:
                break
            curr.append(candidates[i])
            self.dfs(candidates, target - candidates[i], i, d+1, e, curr, ans)
            curr.pop()

Q4. Merge Intervals【Medium】
题目理解:1)输入:一个Interval列表(intervals),这里Interval为题目设定的一种数据结构,包含起始位置,且为闭区间
                2)输出:Interval列表,表示将原输入进行区间融合后的结果,要求输出的列表中的每个区间没有交集

解决方法:排序。将原数组按照start从小到大排序,之后逐个遍历更新即可。若一个interval的start小于前一个interval的end,则进行融合。原理和实现都比较简单,就不赘述了。具体实现如下:

class Solution(object):
    def merge(self, intervals):
        intervals.sort(key = lambda x: x.start)
        ans = []
        for interval in intervals:
            if not ans or interval.start > ans[-1].end:
                ans.append(interval)
            else:
                ans[-1] = Interval(ans[-1].start, max(interval.end, ans[-1].end))
        return ans

Q5. Construct Binary Tree from Preorder and Postorder Traversal 【Medium】
题目理解:1)输入:两个list,分别为先序遍历pre和后续遍历post。其中pre和post中所有元素均不重复
                2)输出:二叉树(root),使得其先序遍历和后续遍历和pre、post相对应。

解决方法: dfs。根据先序遍历和后续遍历的特点可以知道,对于所有子树,先序遍历的根节点在最前,相应的后续遍历根节点在最后。所以我们可以依据这个特点对原数组分段重组。自定义递归函数build(self, pre, post, i, j, n),i为pre中的位置(根节点位置),j为post中的起始位置,n表示该子树的长度,对于整棵二叉树来讲,n = len(pre),每次递归调用时,需要分别分段定义左右子树的范围和长度。具体实现过程如下:

class Solution(object):
    def constructFromPrePost(self, pre, post):        
        n = len(pre)
        return self.build(pre, post, 0, 0, n)
        
    def build(self, pre, post, i, j, n):
        if n == 0:
            return None
        root = TreeNode(pre[i])
        if n == 1:
            return root
        k = j
        while pre[i+1] != post[k]:
            k += 1
        l = k - j + 1
        root.left = self.build(pre, post, i+1, j, l)
        root.right = self.build(pre, post, i+1+l, k+1, n-l-1)
        return root

评分

参与人数 1大米 +3 收起 理由
amcw7777 + 3 加油!

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-3-30 07:02:29 | 只看该作者
全局:
Day 18:

Q1. Flip String to Monotone Increasing 【Medium】
题目理解:1)输入:字符串S,里面仅包含“0”、“1”
                2)输出:整数,表示将S变成单调递增需要翻转的最小位数
                3)规则:只能将“0”翻转为“1”,或者将“1”翻转为“0”

解决方法:1)prefix + suffix。原题要求将S变为单调递增,可以理解为将前i个元素变为“0”并将后n-i个元素变为“1”需要进行反转的次数。 具体实现如下(python):

class Solution(object):
    def minFlipsMonoIncr(self, S):        
        P = [0] #P[i]用于表示原数组到第i位为止的substring有几个1
        n = len(S)
        for i in range(0, n):
            if S[i] == "1":
                P.append(P[-1] + 1)
            else:
                P.append(P[-1])
        ans = 20000
        for j in range(0, n+1):
            ans = min(ans, P[j] + n-j - (P[-1] - P[j]))
        return ans

                2)动态规划。我们使用dp0和dp1两个数组辅助计算。计算以每个i结尾的substring变得符合要求时,需要进行的操作。其中,dp0[i]表示将0~i的substring以0结尾时需要操作的次数,相应的,dp1[i]表示将表示将0~i的substring以1结尾时需要操作的次数。具体实现如下:

class Solution(object):
    def minFlipsMonoIncr(self, S):        
        dp0 = [0]
        dp1 = [0]
        n = len(S)
        for i in range(0, n):
            if S[i]=="0":               
                dp1.append(min(dp0[-1], dp1[-1])+1)
                dp0.append(dp0[-1])
            else:               
                dp1.append(min(dp0[-1], dp1[-1]))
                dp0.append(dp0[-1]+1)
        return min(dp0[-1], dp1[-1])

Q2. 3Sum With Multiplicity 【Medium】
题目理解:1)输入:整数列表A,整数target。其中A
的元素可以重复但每次使用时仅可使用一次
                2)输出:整数。题目要求在A中找任意3个数似的他们的和等于target,求所有满足条件的结果的数量

解决方法: 利用双指针+hashtable。先将原数组进行排序,建立hashtable来记录原数组中distinct数字出现的次数。因为已知三个数的和,因此可以用双指针来指代3个数,在进行计数时,需要分别讨论3个数中存在相同元素的情况。同时利用排序+指针可以进行剪枝。具体实现如下(python):

class Solution(object):
    def threeSumMulti(self, A, target):
        d = {}
        n = len(A)
        for i in range(0, n):
            if A[i] not in d:
                d[A[i]] = 1
            else:
                d[A[i]] += 1
        ans = 0
        for a in d:
            for b in d:
                if b < a:
                    continue
                c = target - a - b
                if c not in d or c < b:
                    continue
                if c == a and a == b:
                    ans += self.count(d[a], 3)
                elif a == b:
                    ans += self.count(d[a], 2) * d[c]               
                elif b == c:
                    ans += self.count(d[b], 2) * d[a]
                else:
                    ans += d[a] * d[b] * d[c]
        MAX = 10**9 + 7
        ans = ans%MAX
        return ans
     
    def f(self, n):
        if n < 0:
            return -1
        if n == 0:
            return 1
        ans = 1
        for i in range(1, n+1):
            ans *= i
        return ans
   
    def count(self, n, a):
        if n < a:
            return 0
        if n == a:
            return 1
        return self.f(n)/self.f(a)/self.f(n-a)
            
Q3. Implement Rand10() Using Rand7() 【Medium】
题目理解:要求利用题目给定的函数rand7(用于产生从1~7的随机数)生成1~10的随机数,且每个数出现的概率相同

解决方法:利用一个7*7的二维矩阵产生49个格子,每个格子的概率相同。我们选取前40个用于产生随机数,如果落在了最后9个格子中,则重新执行rand7,直到结果落回前40个格子,之后可以根据mod(10)的结果定义输出的随机数。具体实现如下(python):

class Solution(object):
    def rand10(self):        
        index = 1000000000
        while index >= 40:
            index = 7*(rand7() - 1) + rand7() - 1
        return index%10 + 1

Q4. 901【Medium】
题目理解:1)输入:price,表示每天股票的价格
                2)输出:整数,表示之前有几天股票价钱低于当前价格。如果是第一天或者前面都大于当前,则定义为1

解决方法:递推并利用stack。比较当前价格和stack中的最后一个价格,若当前价格高,则pop出之前的价格并继续比较,直至当前价格小于stack最后一个价格,每次pop出一个结果后,当前价格的对应结果加上pop出来的价钱对应的结果。确保了stack 中所有元素都是递减的(不增)。具体实现如下:

class StockSpanner(object):

    def __init__(self):
        self.stack = []

    def next(self, price):        
        weight = 1
        while self.stack and self.stack[-1][0] <= price:
            weight += self.stack[-1][1]
            self.stack.pop()
        self.stack.append((price, weight))
        return weight

Q5. Combination Sum II 【Medium】
题目理解: 1)输入:list[int],candidates和整数target,其中candidates存在重复元素,每个元素只可以使用1次
                2)输出:list[list[int]],表示candidates中所有和为target的整数列表,要求最终结果distinct

解决方法:dfs。和昨天的Q3类似,第一种方法就是用昨天几乎一样的代码,只不过每次递归的时候跳过当前元素。得到所有结果后,遍历一次记录distinct的即可。另一种方法依然是类似的递归过程,只是在实现过程中,直接排除掉重复的结果,这样的话会少做一些重复的步骤,同时少了去重的过程,相比前一种方法会快一些。具体实现过程如下:
1)class Solution(object):
    def combinationSum2(self, candidates, target):        
        candidates.sort()
        n = len(candidates)
        curr = []
        ans = []
        self.dfs(candidates, target, 0, curr, ans)
        distinct = []
        for item in ans:
            if item not in distinct:
                distinct.append(item)
               
        return distinct
        
    def dfs(self, candidates, target, s, curr, ans):
        if target == 0:
            ans.append(curr[:])
            return
        n = len(candidates)
        for i in range(s, n):
            if candidates[i]>target:
                break
            curr.append(candidates[i])
            self.dfs(candidates, target - candidates[i], i+1, curr, ans)
curr.pop()

2)class Solution(object):
    def combinationSum2(self, candidates, target):        
        candidates.sort()
        ans, curr = [],[]
        self.dfs(candidates, target, 0, curr, ans)
        return ans
   
    def dfs(self, candidates, target, s, curr, ans):
        if target ==0:
            ans.append(curr[:])
            return
        n = len(candidates)
        for i in range(s, n):
            if candidates[i] > target:
                return
            if i > s and candidates[i]==candidates[i-1]:
                continue
            curr.append(candidates[i])
            self.dfs(candidates, target-candidates[i], i+1, curr, ans)
            curr.pop()
回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-4-2 08:52:11 | 只看该作者
全局:
Day 19:

Q1. Possible Bipartition 【Medium】
题目理解:1)输入:整数N和list[list[int]] dislikes,其中N表示一共有N个人,dislikes中每个元素dislikes[i] = [a, b]表示a和b俩个人互相不喜欢对方,互相不喜欢的人不能分配在同一个组中
                2)输出:bool变量,表示能否根据dislikes中的关系将题中已知的N个人分成2个小组

解决方法:1)dfs。可以先建立一个N*N的空白list[list[]] g,其中g[i]用于记录第i 个人不喜欢的人的list 。之后我们利用dfs对这N个人进行染色,假设我们只想分成红色和蓝色两组。那么,对于i,如果他是红色,那么g[i]中的所有人都只能是蓝色。当染色出现冲突时,则说明不能将这些人只分在2组中,直接返回False。当所有g[i]都遍历过且所有人都能染色成功,那么最后返回True。具体实现如下(python):

class Solution(object):
    def possibleBipartition(self, N, dislikes):
        self.g = [[] for row in range(0,N) ]
        for d in dislikes:
            self.g[d[0]-1].append(d[1]-1)
            self.g[d[1]-1].append(d[0]-1)
        self.colors = [0]*N
        for i in range(0, N):
            if self.colors[i] == 0 and not self.dfs(i, 1):
                return False
        return True
   
    def dfs(self, curr, color):
        self.colors[curr] = color
        for nxt in self.g[curr]:
            if self.colors[nxt] == color:
                return False
            if self.colors[nxt] == 0 and not self.dfs(nxt, -color):
                return False
        return True

                2)bfs。跟dfs的第一步一样,依然用g将原来的dislikes中的关系展开 。之后每个在对0~N-1这些人的index进行遍历时,g[i]就可以作为一层元素一起被找到,利用一个list/queue记录对未染色的人,并依次进行染色并更新。同样的,当中间任何地方出现染色冲突就直接返回False。当所有人都成功染色,则可以返回True。具体实现如下:

class Solution(object):
    def possibleBipartition(self, N, dislikes):        
        g = [[] for row in range(0, N)]
        for d in dislikes:
            g[d[0]-1].append(d[1]-1)
            g[d[1]-1].append(d[0]-1)
        
        colors = [0]*N
        q = []
        
        for i in range(0, N):
            if colors[i]!=0:
                continue
            colors[i] = 1
            q.append(i)
            while q:
                curr = q[0]
                q.pop(0)
                for nxt in g[curr]:
                    if colors[nxt] == colors[curr]:
                        return False
                    if colors[nxt] == 0:
                        q.append(nxt)
                        colors[nxt] = -colors[curr]
        return True

Q2. 【Medium】
题目理解:1)输入:整数列表piles,表示一排石头,其中每个piles[i]表示第i堆石头的数量
                2)输出:bool结果,如果Alex胜利则返回True,反之返回False
                3)规则:已知piles的长度为偶数,每轮游戏中,Alex和Lee可以分别从剩下的石头的两端取走一堆石头, 每人只能取一堆,且Alex先取。同时游戏中设定两个人都是发挥最理想的情况

解决方法: 1)根据题目描述,因为所有石头一共有偶数堆,那么在两个人都发挥最好的前提下,可以知道每个人都要保证自己的相对分数更大。那么Alex在先手的情况下,他总是可以保证相对分数为正,也就是说他最后一定比Lee拿到的多,因此这是一个谁先拿谁一定赢的游戏,直接返回True即可

                2)因为这道题是给定了特殊的条件,当石头堆为奇数时则无法直接成立。那么从算法角度考虑, 因为每个人操作的规则一致且每次操作都只与上一次的操作相关,所以可以用递归/递推来解决。具体代码如下:

class Solution(object):
    def stoneGame(self, piles):        
        n = len(piles)
        dp = [[0]*n for row in range(n)]
        for i in range(0, n):
            dp[i][i] = piles[i]
        for l in range(2, n+1): #l表示剩下的石头堆的长度
            for i in range(0, n-l+1):#i表示起始坐标
                j = i+l-1
                dp[i][j] =max(piles[i] - dp[i+1][j], piles[j] - dp[i][j-1])
        return dp[0][n-1]>0
            
Q3. Length of Longest Fibonacci Subsequence 【Medium】
题目理解:1)输入:整数列表A,其中每个元素严格递增
                2)输出:整数,表示A中能够构成的满足斐波那契数列条件的组序列的最长长度

解决方法:动态规划。解题关键在于不仅需要两个元素一起来锁定递归条件。根据斐波那契数列的性质,F[k] = F[i] + F[j],所以每个坐标k需要找到一对满足条件的(i, j),同时找到以第i、j位结尾的斐波那契子序列的长度,来对数据进行更新。具体实现如下(python):

class Solution(object):
    def lenLongestFibSubseq(self, A):
        d = {}
        n = len(A)
        for i in range(n):
            d[A[i]] = i
        dp = [[2]*n for row in range(n)]
        ans = 0
        for j in range(0, n):
            for k in range(j+1, n):
                ai = A[k] - A[j]
                if ai >= A[j]:
                    break
                if ai not in d:
                    continue
                i = d[ai]
                dp[j][k] = dp[i][j] + 1
                ans = max(dp[j][k], ans)
        return ans

Q4. Minimum ASCII Delete Sum for Two Strings 【Medium】
题目理解:1)输入:两个字符串 s1、s2
                2)输出:整数,表示从s1和s2中删掉的元素的ASCII码之和,使得s1和s2剩下的部分完全相同,且删掉的结果为最小值

解决方法:1)递推 。根据s1、s2的substring逐步进行计算。具体实现如下:
class Solution(object):
    def minimumDeleteSum(self, s1, s2):        
        m = len(s1)
        n = len(s2)
        A = [[0]*(n+1) for row in range(m+1)]

        for i in range(0, m+1):
            for j in range(0, n+1):
                if i == 0 and j == 0:
                    A[i][j] = 0
                elif i == 0:
                    A[i][j] = A[i][j-1] + ord(s2[j-1])
                elif j == 0:
                    A[i][j] = A[i-1][j] + ord(s1[i-1])
                else:
                    if s1[i-1] != s2[j-1]:
                        A[i][j] = min(A[i][j-1] + ord(s2[j-1]), A[i-1][j] + ord(s1[i-1]))
                    if s1[i-1] == s2[j-1]:
                        A[i][j] = A[i-1][j-1]
        return A[m][n]

                2)记忆化递归。跟递推类似,利用相似的递推关系作为递归函数,递推的起始条件对应递归的终止条件。采用记忆化递归是为了防止递归深度过大而超时。具体实现如下:

class Solution(object):
    def minimumDeleteSum(self, s1, s2):
        l1 = len(s1)
        l2 = len(s2)
        self.m_ = [[2000000]*(l2+1) for row in range(0, l1+1)]
        return self.dfs(s1, l1, s2, l2)
   
    def dfs(self, s1, l1, s2, l2):
        if l1 == 0 and l2 == 0:
            return 0
        if self.m_[l1][l2] != 2000000:
            return self.m_[l1][l2]
        if l1 == 0:
            self.m_[l1][l2] = self.dfs(s1, l1, s2, l2-1) + ord(s2[l2-1])
            return self.m_[l1][l2]
        if l2 == 0:
            self.m_[l1][l2] = self.dfs(s1, l1-1, s2, l2) + ord(s1[l1-1])
            return self.m_[l1][l2]
        if s1[l1-1] == s2[l2-1]:
            self.m_[l1][l2] = self.dfs(s1, l1-1, s2, l2-1)
            return self.m_[l1][l2]
        self.m_[l1][l2] = min(self.dfs(s1, l1, s2, l2-1) + ord(s2[l2-1]), self.dfs(s1, l1-1, s2, l2) + ord(s1[l1-1]))
        return self.m_[l1][l2]
回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2019-4-11 05:20:19 | 只看该作者
全局:
Day 20

Q1. Global and Local Inversions 【Medium】
题目理解: 1)输入:整数列表A,其中包含从0~N-1的所有整数
                 2)输出:bool结果,表示A中的global inversions和local inversions数量是否相同,相同则输出True,否则,输出False
                 3)Global inversions:表示对于任何坐标i < j ,同时满足0 <= i < j < N 和 A[i] > A[j]
                 4)Local inversions:表示对于任何坐标i,同时满足 0 <= i < N 和A[i] > A[i+1]

解决方法:1)根据列表A的特性,元素为连续整数0~N-1,因此我们可以知道Global inversions >= Local inversions。因此可以直接判断第i个元素A[i]和i的差的绝对值是否大于1,如果存在abs(A[i] - i) > 1,说明在第i位后面一定有2个元素小于A[i],也就是说global > local 。具体过程如下:

class Solution(object):
    def isIdealPermutation(self, A):
        n = len(A)
        for i in range(0, n):
            if abs(A[i] - i) > 1:
                return False
        return True

                 2)mergeSort。利用递归的思想,不断将数组分解成左右两半,分别计算两部分内部的inversion数量,并对两部分分别排序,在将两部分进行合并时(边排序边合并),然后根据greedy直接计算两个数组之间产生的inversion数量。具体过程如下:

class Solution(object):
    def isIdealPermutation(self, A):
        local = 0
        n = len(A)
        for i in range(0, n-1):
            if A[i] > A[i+1]:
                local += 1
        temp = [0]*n
        g = self.mergeSort(A, 0, n-1, temp)
        
        return local == g
   
    def mergeSort(self, A, l, r, temp):
        if l >= r:
            return 0

        m = l + (r - l)/2
        inv = self.mergeSort(A, l, m, temp) + self.mergeSort(A, m+1, r, temp)
        
        i = l
        j = m+1
        k = 0
        
        while i <= m and j <= r:
            if A[i] > A[j]:
                temp[k] = A[j]
                k += 1
                j += 1
                inv += m - i + 1
            else:
                temp[k] = A[i]
                k += 1
                i += 1
        
        while i <= m:
            temp[k] = A[i]
            k += 1
            i += 1
        while j <= r:
            temp[k] = A[j]
            k += 1
            j += 1
        
        A[l:r+1] = temp[:r-l+1]
        return inv

Q2. Permutation in String 【Medium】
题目理解: 1)输入:两个字符串s1、s2(仅包含小写字母)
                 2)输出:bool结果,表示s2中是否存在连续的一段字符串s,刚好包含s1中所有字符

解决方法:先考虑特殊情况,比如s2长度小于s1,或者s2为空,直接返回False,如果s1为空,则返回True。之后先遍历s1,利用一个list(target)先记录每个字母出现的次数,另s1长度为m,s2长度为n。之后在遍历s2时,利用sliding window的想法,保证每次只记录长度为m的字符串里字符的数量,用另一个list(d)记录遍历s2时的字符数量,循环中任何时候d==target,即返回True。当全部遍历完时,若仍未返回,最后返回False。具体实现如下:


class Solution(object):
    def checkInclusion(self, s1, s2):        
        m = len(s1)
        n = len(s2)
        if m>n or n==0:
            return False
        target = [0]*26
        d = [0]*26
        for c in s1:
            target[ord(c) - ord('a')] += 1
        for i in range(0, n):
            d[ord(s2[i]) - ord('a')] += 1
            if i>m-1:
                d[ord(s2[i-m]) - ord('a')] -= 1
            if d == target:
                return True            
        return False

Q3.  Smallest Subtree with all the Deepest Nodes 【Medium】
题目理解: 1)输入:二叉树根节点(root)
                 2)输出:一个treenode,为包含深度最大的节点的最小子树的根节点

解决方法:递归。自定义一个递归函数dfs(root),因为题目要求返回包含最深的叶子结点的最小子树,因此我们在计算每个节点的深度时,同时需要记录其父节点。因此dfs 返回root对应的深度和root的父节点两个结果。在dfs内部,需要对左右子树调用dfs来实现递归,在计算每个节点深度的时候,需要比较左右子树的深度,取较大值+1。具体实现过程如下:

class Solution(object):
    def subtreeWithAllDeepest(self, root):
        pair = self.dfs(root)
        return pair[1]
   
    def dfs(self, root):
        if not root:
            return [-1, None]
        l = self.dfs(root.left)
        r = self.dfs(root.right)
        dl = l[0]
        dr = r[0]
        if dl == dr:
            return [dl+1, root]
        elif dl > dr:
            return [dl+1, l[1]]
        else:
return [dr+1, r[1]]

Q4. Contiguous Array 【Medium】
题目理解: 1)输入: 整数列表nums,仅包含0、1
                 2)输出:整数,表示nums中满足最长的连续子序列的长度,满足该连续子序列中0、1的数量相同

解决方法:直接计数。首先考虑特殊情况(nums为空)。N = len(nums)。之后用一个长度为n的新list对原数组进行计数,计作count。当nums[0] = 1时,count[0] = 1;当nums[0] = 0时,count[0] = -1。之后从1~n对index循环。每次遇到1则count[i] = count[i-1]+1, 否则count[i] = count[i-1]-1。对于i<j, count[i] = count[j]时,则从i+1~j的子序列满足0、1数量相同。同时需要考虑特殊情况,如果count[i] = 0,那么从0~i可以构成满足条件的序列。因此可以另外建立一个hashtable用来记录每个distinct的非零元素count[i]的坐标。在循环中不断更新ans。具体实现如下:

class Solution(object):
    def findMaxLength(self, nums):      
        n = len(nums)
        if n == 0:
            return 0
        count = [0]*n
        d = {}
        if nums[0] == 1:
            count[0] = 1
        else:
            count[0] = -1
        ans = 0
        for i in range(1, n):
            if nums[i] == 1:
                count[i] = count[i-1] + 1
            else:
                count[i] = count[i-1] - 1
        for i in range(0, n):
            if count[i] == 0:
                ans = max(ans, i+1)
            elif count[i] not in d:
                d[count[i]] = i
            else:
                ans = max(ans, i - d[count[i]])
            
        return ans

Q5. All Nodes Distance K in Binary Tree 【Medium】
题目理解: 1)输入:二叉树根节点(root),target目标节点,整数K
                 2)输出:一个list,包含所有满足条件的treenode上的值,输出列表中的所有元素对应的节点到target节点的距离(path长度)都为K。
                 3)原二叉树中所有节点的元素值都不同

解决方法:将原二叉树转化为无向图,利用递归函数和bfs解决。先自定义dfs用来创建子节点到其父节点的对应关系,之后以target节点为中心进行逐层遍历,同时利用hashset来记录已经遍历过的节点防止进入到死循环中。具体实现如下:

class Solution(object):
    def distanceK(self, root, target, K):
        def dfs(node, parent = None):
            if node:
                node.par = parent
                dfs(node.left, node)
                dfs(node.right, node)
        dfs(root, parent = None)
        q = collections.deque([(target, 0)])
        seen = {target}
        while q:
            if q[0][1] == K:
               
        
        
        
        
        
        
        def dfs(node, par = None):
            if node:
                node.par = par
                dfs(node.left, node)
                dfs(node.right, node)

        dfs(root)

        queue = collections.deque([(target, 0)])
        seen = {target}
        while queue:
            if queue[0][1] == K:
                return [node.val for node, d in queue]
            node, d = queue.popleft()
            for nei in (node.left, node.right, node.par):
                if nei and nei not in seen:
                    seen.add(nei)
                    queue.append((nei, d+1))

        return []
回复

使用道具 举报

🔗
 楼主| Wangjingru_1995 2020-6-10 05:55:16 | 只看该作者
全局:
【帮公司转】
北加湾区San Jose工程科技公司Nodesus Inc.有一些工程类实习和兼职的机会,要求最好有机械ME背景(电子EE背景也可以考虑),非常适合在校学生或者刚毕业不久的同学,非常好的积累实际工程项目经验的机会!目前也可以考虑远程实习的情况。有兴趣的同学,请联系info@nodesus.com, 并附上简历。谢谢!!!

【BTW】
公司对CPT/OPT友好,因为公司很新,目前在快速发展阶段,每个人都能得到很好的锻炼机会,并且会考虑个人发展加入不同项目学习,项目合作对象有各种大小公司(大到Google Apple, 小到10人的创业公司),积累经验/扩大network的福音!我本人ME的本科+研究生,去年和老公一起来湾区,因为ME new grad没经验很难找到full time position就刷题转码,结果在OPT失业期快到的时候机缘巧合发现这个机会入职的,一开始就和公司co-founder们一起工作,大家都非常nice!给我介绍行业现状等,也会帮我一起找各种机会,积累了不少经验(ME专业的孩子们都懂没有经验多难融入行业吧hh)。经过不断努力,公司拿到了很多新的项目,比较缺人手,所以我也希望把这个机会传递下去~希望能帮到更多人
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表