• 2.1 数据结构---数组


    (一)数组

    总结:

      利用序:理解二分查找

      利用前缀和:查找、计算、排序

      理解数组:map

      用数组实现高级数据结构:一般树(存每个节点的父亲【并查集】);二叉树(下标从1开始a[i]的儿子是a[i*2]和a[i*2+1])(堆)

      简单题:分治法求逆序对数;有序数组归并;两个有序数组的中位数;两头扫的方法(2-SUM,3-SUM)

    (二)算法

    一、排列、组合、子集

    1.子集

    (1)Leetcode78:子集

    题目描述:给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    说明:解集不能包含重复的子集。

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

    思路:

    1.回溯法

    2.Python的extend功能

    方法1代码:

    class Solution:
        def subsets_way3(self,nums):
            if not nums:
                return []
            res = []
            lens = len(nums)
    
            def helper(idx,temp_list):
                res.append(temp_list)
                for i in range(idx,lens):
                    helper(i+1,temp_list+[nums[i]])
    
            helper(0,[])
            return res

    方法2代码:

    def subsets_way1(nums):
        result = [[]]
        for x in nums:
            result.extend([subset + [x] for subset in result])
        return result

    (2)Leetcode90:子集II

    题目描述:给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    说明:解集不能包含重复的子集。

    这道题与78题区别在于,数组里包含了重复数组,一般有3种办法:

    1.用上面一题方法,把相同的不加入

    2.在递归时候,加个判断,发现此位置和前位置相等,就跳过(必须是有序列表)

    3.先按78的思路,把重复的也算出来,再用dict遍历一遍,去重(这个方法比较笨重)

    方法1、2代码:

    class Solution1:
        def subsets2(self,nums):
            if not nums:
                return []
            n = len(nums)
            res = []
            nums.sort()
            def helper(idx,temp_list):
                if temp_list not in res:#相同的不加入
                    res.append(temp_list)
                for i in range(idx,n):
                    helper(i+1,temp_list+[nums[i]])
    
            def helper2(idx,temp_list):
                res.append(temp_list)
                for i in range(idx,n):
                    if i > idx and nums[i] == nums[i-1]:
                        continue
                    helper(i+1,temp_list+[nums[i]])
            helper(0,[])
            return res

    方法3代码:

    class Solution:
        def subsetsWithDup(self, nums):
            """
            :type nums: List[int]
            :rtype: List[List[int]]
            """
            result = [[]]
            for x in nums:
                result.extend([subset + [x] for subset in result])
            # print("result",result)
            return self.transfer(result)
    
        def transfer(self, res):#去重
            Res = {}
            for key,value in enumerate(res):
                res[key] = sorted(value,reverse=True)
            for key,value in enumerate(res):
                if tuple(value) not in Res:
                    Res[tuple(value)] = 1
                Res[tuple(value)] += 1
            res = [list(key) for (key,value) in Res.items()]
            return res
    

       

    2.全排列

    (1)Leetcode46:全排列

    题目描述:给定一个没有重复数字的序列,返回其所有可能的全排列。

    示例:

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

    思路:

    1.直接调用Python的itertools.permutations包,不过返回的是tuple类型的;

    2.回溯法,递归得到结果

    (1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀);

    (2)出口:如果只有一个元素的全排列,则说明已经排完,则输出数组;

    (3)不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等到出口,出口出去后还需要还原数组;

    方法1代码:

    import itertools
    def permutations1(nums):
        return list(itertools.permutations(nums,len(nums)))

    方法2代码:

    res = []
    def permutations2(s,k):
        if k == len(s):
            res.append(s.copy())
            # print(s)
    
        #第0个元素和后面的每个元素交换
        #第1个元素和后面的每个元素交换
        #......
        #k:当前的交换位置(关注点),与其后的元素交换
        for i in range(k,len(s)):
            s[i],s[k] = s[k],s[i]#试探
            permutations2(s,k+1)
            s[i], s[k] = s[k], s[i]  # 回溯
            #比如123交换之后变为132,那么第二次循环的时候应该从123开始,
            #而不是从132开始,所以要回溯
    

    (2)Leetcode47:全排列II

    题目描述:给定一个可包含重复数字的序列,返回所有不重复的全排列。

    示例:

    输入: [1,1,2]
    输出:
    [
      [1,1,2],
      [1,2,1],
      [2,1,1]
    ]
    两种思路:

    1.一种是列出所有的排列,再去重(笨重的方法)

    2.递归,交换之前先判断是否已经出现重复的元素,若存在,就不交换

    方法1代码:

    import itertools
    class Solution:
        def permuteUnique(self,nums):
            return list(itertools.permutations(nums,len(nums)))
    
        def unique_permutation(self,candidates):#去重,把每个排列放入字典中,去掉重复的
            candidates.sort()
            result = []
            Re = []
            dict_ = {}
            if len(result) == 1:
                return result
            else:
                for i in candidates:
                    if i not in dict_:
                        dict_[i] = 1
                    else:
                        dict_[i] += 1
            for item in dict_:
                Re.append(item)
            return Re

    方法2代码:依旧全排列的思路,只不过需要定义一个set来存储已经交换过的元素值,也就是已经做过某个排列的首元素的值存放在set中,避免重复这种情形。

    import copy
    class Solution1(object):
        def permuteUnique(self, nums):
            self.res = []
            self.f(nums,k=0)
            return self.res
    
        def f(self,num_list, k):
            begindata = set()  # 每层递归都要重置
            if k == len(num_list):
                print(num_list)
                tmp = copy.copy(num_list)
                self.res.append(tmp)
            for i in range(k, len(num_list)):
                if num_list[i] in begindata:  # 已经做过某个排列首元素,则跳过这种情况
                    continue
                begindata.add(num_list[i])
    
                num_list[i],num_list[k] = num_list[k],num_list[i]#交换两个元素的位置
                self.f(num_list, k + 1)
                num_list[i], num_list[k] = num_list[k], num_list[i]#回溯
    
    S = Solution1()
    res = S.permuteUnique(nums=[1,2,2])
    print(res)
    

    3.组合总和

    (1)Leetcode39:组合总和

    题目描述:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。

    说明:所有数字(包括 target)都是正整数。解集不能包含重复的组合。

    示例:

    输入: candidates = [2,3,6,7], target = 7,
    所求解集为:
    [
      [7],
      [2,2,3]
    ]
    

     思路1:回溯法递归求解

    class Solution:
        def combinationSum(self, candidates, target):
            if not candidates:
                return []
            if min(candidates) > target:
                return []
            candidates.sort()
            res = []
    
            def helper(candidates_,target_,temp_list):
                if target_ == 0:
                    # print(temp_list)
                    res.append(temp_list)
                if target < 0:
                    return
                for i in range(len(candidates_)):
                    # print(temp_list,candidates_[i])
                    if candidates_[i] > target_:
                        break
                    helper(candidates_[i:],target_-candidates_[i],temp_list+[candidates_[i]])
    
            helper(candidates,target,[])
            return res
    

    (2)Leetcode40:组合总和II

    题目描述:给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用一次。

    说明:所有数字(包括目标数)都是正整数。解集不能包含重复的组合。

    示例:

    输入: candidates = [10,1,2,7,6,1,5], target = 8,
    所求解集为:
    [
      [1, 7],
      [1, 2, 5],
      [2, 6],
      [1, 1, 6]
    ]
    

    思路1:回溯法,递归求解,因为不能重复使用列表中的元素,所以下一次递归要从下个元素开始(不包括自身)

    class Solution1:
        def combinationSum2(self, candidates, target):
            if not candidates:
                return []
            if min (candidates) > target:
                return []
            candidates.sort ()
            res = []
    
            def helper(candidates_, target_, temp_list):
                if target_ == 0 and temp_list not in res:
                    # print(temp_list)
                    res.append (temp_list)
                if target < 0:
                    return
                for i in range (len (candidates_)):
                    # print(temp_list,candidates_[i])
                    if candidates_[i] > target_:
                        break
                    helper (candidates_[i+1:], target_ - candidates_[i], temp_list + [candidates_[i]])
    
            helper(candidates, target, [])
            return res
    

    4.分割回文串

    (1)Leetcode131:分割回文串

    题目描述:给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的分割方案。

    示例:

    输入: "aab"
    输出:
    [
      ["aa","b"],
      ["a","a","b"]
    ]

    思路1:回溯法

    题目要求返回所有的可能方案,所以依旧采用回溯算法。循环查看当前字符串的每一个可切分位置位;判断若在当前位置切分,前半部分是否是回文串。若是,则将前半部分存入当前解,并递归分割后半部分。
    例如输入字符串为示例:
    |a  |a  |b  |
    0 1 2 3 
    首先判断分割位1,发现前半部分‘a’是回文串,将‘a’存入temp_list,将后半部分‘ab’用作递归。当遍历到字符串尾端时,递归结束,将temp_list加入的res,最终返回res.
    class Solution (object):
        def partition(self, s):
            """
            :type s: str
            :rtype: List[List[str]]
            """
            if not s:
                return []
            res = []
            lens = len(s)
            def helper(idx,temp_list):
                if idx == lens:
                    res.append(temp_list)
                for i in range(idx,lens):
                    if s[idx:i+1] == s[idx:i+1][::-1]:
                        helper(i+1,temp_list+[s[idx:i+1]])
            helper(0,[])
            return res
    
    S = Solution()
    res = S.partition(s='aab')
    print(res)
    

     

    二、动态规划

    三、查找和排序

    1.二分查找

    (1)局部极小值

    2.元素交换

    (1)第一个缺失的正整数

    3.排序、中位数

    (1)元素最大间距离

    (2)众数

    4.归并

    5.位运算

    (1)只出现一次的数

    6.前缀和的应用

     

    参考文献:

    【1】回溯算法系列




  • 相关阅读:
    设计模式总结:单例模式(以及多线程、无序写入、volatile对单例的影响)
    android的WebView进度条
    三角形类内置成员函数(看看吧。。)
    VGA接口之显示彩色条
    Java I/O流操作(二)缓冲流
    oracle 单引号 双引号 连接符
    2013腾讯编程马拉松初赛(3月22)赛题及第2题代码(C++)
    Java I/O流操作(一)入门篇和System和Properties类介绍
    POJ 3264 Balanced Lineup
    成都行(二)
  • 原文地址:https://www.cnblogs.com/nxf-rabbit75/p/10275635.html
Copyright © 2020-2023  润新知