第五章 Depth first search

dfs:深度优先搜索

  1. 岛屿的个数
    中文English
    给一个 01 矩阵,求不同的岛屿的个数。

0 代表海,1 代表岛,如果两个 1 相邻,那么这两个 1 属于同一个岛。我们只考虑上下左右为相邻。

Example
样例 1:

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

输入:
[
[1,1]
]
输出:
1

# #深度优先搜索 + 访问数组 + 方向数组
class Solution:
    def numIslands(self,grid):
        if not grid:
            return 0

        m,n = len(grid),len(grid[0])
        # print("m: ",m)
        # print("n: ",n)

        visited = set()
        numberOfIsland = 0
        dirs = [
            (0,1), #right
            (0,-1),#left
            (1,0),#down
            (-1,0)#up
        ]

        for i in range(m):
            for j in range(n):
                #
                if self.check(grid,i,j,visited):
                    self.dfs(grid,i,j,visited,dirs)

                    numberOfIsland += 1
        return numberOfIsland

    def dfs(self,grid,x,y,visited,dirs):
        visited.add((x,y))
        # print("visited: ",visited)

        for dx, dy in dirs:
            nx = x+dx
            ny = y+dy
            if self.check(grid,nx,ny,visited):
                self.dfs(grid,nx,ny,visited,dirs)

    def check(self,grid,x,y,visited):
        m,n = len(grid),len(grid[0])
        if x >= 0 and x <m and y >= 0 and y < n and grid[x][y] and (x,y) not in visited:
            return True
        return False

if __name__ == '__main__':
    a = Solution()
    b = [
[1,1,0,0,0],
[0,1,0,0,1],
[0,0,0,1,1],
[0,0,0,0,1]
]
    print(a.numIslands(b))

431—找无向图的连通块

描述

找出无向图中所有的连通块。
图中的每个节点包含一个label属性和一个邻接点的列表。(一个无向图的连通块是一个子图,其中任意两个顶点通过路径相连,且不与整个图中的其它顶点相连。)

注意事项

每个连通块内部应该按照label属性排序

说明

Learn more about representation of graphs

样例

给定图:

A------B  C
 \     |  | 
  \    |  |
   \   |  |
    \  |  |
      D   E

返回 {A,B,D}, {C,E}。其中有 2 个连通块,即{A,B,D}, {C,E}

注意事项

每个连通块内部应该按照label属性排序


class UndirectedGraphNode:
    def __init__(self,x):
        self.label = x
        self.neighbors = []

from collections import defaultdict

class Solution:
    def connectedSet(self,nodes):
        if not nodes:
            return []

        components = []
        visited = set()
        for node in nodes:
            if node.label not in visited:
                self.findComponent(node,[],components,True,visited)

        return components

    def findComponent(self,node,component,components,isAddToComponents,visited):
        component.append(node.label)
        visited.add(node.label)
        for nei in node.neighbors:
            if nei.label not in visited:
                self.findComponent(nei,component,components,False,visited)

        if isAddToComponents:
            component.sort()
            print(component)
            components.append(component)

if __name__ =='__main__':
    node1= UndirectedGraphNode(1)
    node2 = UndirectedGraphNode(2)
    node3 = UndirectedGraphNode(3)
    node4= UndirectedGraphNode(4)
    node5= UndirectedGraphNode(5)
    node1.neighbors = [node2,node4]
    node2.neighbors = [node1,node4]
    node3.neighbors = [node5]
    node4.neighbors = [node1,node2]
    node5.neighbors = [node3]

    A = Solution()
    nodes = [node1,node2,node3,node4,node5]
    print(A.connectedSet(nodes))

  1. 数字组合
    中文English
    给定一个候选数字的集合 candidates 和一个目标值 target. 找到 candidates 中所有的和为 target 的组合.

在同一个组合中, candidates 中的某个数字不限次数地出现.

Example
样例 1:

输入: candidates = [2, 3, 6, 7], target = 7
输出: [[7], [2, 2, 3]]
样例 2:

输入: candidates = [1], target = 3
输出: [[1, 1, 1]]
Notice
所有数值 (包括 target ) 都是正整数.
返回的每一个组合内的数字必须是非降序的.
返回的所有组合之间可以是任意顺序.
解集不能包含重复的组合.

class Solution:
    def combinationSum(self,candidates,target):
        if not candidates:
            return []

        candidates.sort()
        result = []
        self.dfs(candidates,0,target,[],result)

        return result

    def dfs(self,candidates, startIndex, target, localCombos, result):
        if target == 0:
            result.append(localCombos[:])  #克隆

            return

        for i in range(startIndex,len(candidates)):
            #去重
            if i > startIndex and candidates[i] == candidates[i - 1]:
                continue

            if candidates[i] > target:
                return
            localCombos.append(candidates[i])
            self.dfs(candidates,i,target-candidates[i],localCombos,result)
            localCombos.pop()

if __name__ == '__main__':
    a = Solution()
    tar = 7
    candid = [2,3,6,7]
    print(a.combinationSum(candid, tar))

  1. 分割回文串
    中文English
    给定字符串 s, 需要将它分割成一些子串, 使得每个子串都是回文串.

返回所有可能的分割方案.

Example
样例 1:

输入: “a”
输出: [[“a”]]
解释: 字符串里只有一个字符, 也就只有一种分割方式 (就是它本身)
样例 2:

输入: “aab”
输出: [[“aa”, “b”], [“a”, “a”, “b”]]
解释: 有两种分割的方式.
1. 将 “aab” 分割成 “aa” 和 “b”, 它们都是回文的.
2. 将 “aab” 分割成 “a”, “a” 和 “b”, 它们全都是回文的.
Notice
不同的方案之间的顺序可以是任意的.
一种分割方案中的每个子串都必须是 s 中连续的一段.

class Solution:
    #2019/08/28
    #算法思想:
    #-定义全局结果变量,self.res
    #-对给定的字符串进行深度优先搜索,找出所有可行解,将其放入到全局结果集中
    #-dfs每一个局部可行解使用局部变量保存,满足条件后加入到全局结果集
    def partition(self,s):
        if not s:
            return []

        result = []
        self.dfs(s,[],result)

        return result

#dfs函数职能:
    # 对于给定的String,对其所有切分位置进行尝试,将所有可能的回文切分结果放入到
    # localpartion中,并且将满足条件的
    # LOCALPARTTION加入到全局集resultz中。
    def dfs(self,string,localPartition,result):
        if len(string) == 0:
            result.append(localPartition[:])
            return

        for i in range(1,len(string)+1):
            print("string[:i]: ", string[:i])
            if self.isPalindrome(string[:i]):
                # print(string[:i])
                localPartition.append(string[:i])
                print(localPartition)
                self.dfs(string[i:],localPartition,result)
                localPartition.pop()

    def isPalindrome(self,string):
        if not string:
            return True

        left,right = 0,len(string)-1
        while left < right:
            if string[left] != string[right]:
                return False

            left += 1
            right -= 1
        return True

if __name__ =='__main__':
    a = Solution()
    b = "aab"
    print(a.partition(b))


153—数字组合
描述:

给出一组候选数字©和目标数字(T),找出C中所有的组合,使组合中数字的和为T。C中每个数字在每个组合中只能使用一次。

样例:

给出一个例子,候选数字集合为[10,1,6,7,2,1,5] 和目标数字 8 ,

解集为:[[1,7],[1,2,5],[2,6],[1,1,6]]

注意事项
所有的数字(包括目标数字)均为正整数。
元素组合(a1, a2, … , ak)必须是非降序(ie, a1 ≤ a2 ≤ … ≤ ak)。
解集不能包含重复的组合。

  1. 数字组合 II
    中文English
    给定一个数组 num 和一个整数 target. 找到 num 中所有的数字之和为 target 的组合.

Example
样例 1:

输入: num = [7,1,2,5,1,6,10], target = 8
输出: [[1,1,6],[1,2,5],[1,7],[2,6]]
样例 2:

输入: num = [1,1,1], target = 2
输出: [[1,1]]
解释: 解集不能包含重复的组合
Notice
在同一个组合中, num 中的每一个数字仅能被使用一次.
所有数值 (包括 target ) 都是正整数.
返回的每一个组合内的数字必须是非降序的.
返回的所有组合之间可以是任意顺序.
解集不能包含重复的组合.

  1. 子集 II
    中文English
    给定一个可能具有重复数字的列表,返回其所有可能的子集。

Example
样例 1:

输入:[0]
输出:
[
[],
[0]
]
样例 2:

输入:[1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
Challenge
你可以同时用递归与非递归的方式解决么?

Notice
子集中的每个元素都是非降序的
两个子集间的顺序是无关紧要的
解集中不能包含重复子集

  1. 全排列
    中文English
    给定一个数字列表,返回其所有可能的排列。

Example
样例 1:

输入:[1]
输出:
[
[1]
]
样例 2:

输入:[1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
Challenge
使用递归和非递归分别解决。

Notice
你可以假设没有重复数字。

  1. 带重复元素的排列
    中文English
    给出一个具有重复数字的列表,找出列表所有不同的排列。

Example
样例 1:

输入:[1,1]
输出:
[
[1,1]
]
样例 2:

输入:[1,2,2]
输出:
[
[1,2,2],
[2,1,2],
[2,2,1]
]
Challenge
使用递归和非递归分别完成该题。

  1. 单词拆分 I
    中文English
    给定字符串 s 和单词字典 dict,确定 s 是否可以分成一个或多个以空格分隔的子串,并且这些子串都在字典中存在。

Example
样例 1:
输入: “lintcode”, [“lint”, “code”]
输出: true

样例 2:
输入: “a”, [“a”]
输出: true

  1. 单词拆分II
    中文English
    给一字串s和单词的字典dict,在字串中增加空格来构建一个句子,并且所有单词都来自字典。
    返回所有有可能的句子。

Example
样例 1:

输入:“lintcode”,[“de”,“ding”,“co”,“code”,“lint”]
输出:[“lint code”, “lint co de”]
解释:
插入一个空格是"lint code",插入两个空格是 “lint co de”
样例 2:

输入:“a”,[]
输出:[]
解释:字典为空

  1. 上一个排列
    中文English
    给定一个整数数组来表示排列,找出其上一个排列。

Example
例1:

输入:[1]
输出:[1]
例2:

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

输入:[1,2,3,4]
输出:[4,3,2,1]

Notice
排列中可能包含重复的整数

  1. 下一个排列
    中文English
    给定一个整数数组来表示排列,找出其之后的一个排列。

Example
例1:

输入:[1]
输出:[1]
例2:

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

输入:[4,3,2,1]
输出:[1,2,3,4]
Notice
排列中可能包含重复的整数

10—字符串的不同排列
描述

给出一个字符串,找到它的所有排列,注意同一个字符串不要打印两次

样例

给出 “abb”,返回 [“abb”, “bab”, “bba”]。
给出 “aabb”,返回 [“aabb”, “abab”, “baba”, “bbaa”, “abba”, “baab”]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值