自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

子集問題其實就是模板題!你知道嗎?

網(wǎng)絡(luò)
如果把 子集問題、組合問題、分割問題都抽象為一棵樹的話,那么組合問題和分割問題都是收集樹的葉子節(jié)點,而子集問題是找樹的所有節(jié)點!

[[426614]]

認(rèn)識本質(zhì)之后,這就是一道模板題

子集

力扣題目鏈接:https://leetcode-cn.com/problems/subsets/

給定一組不含重復(fù)元素的整數(shù)數(shù)組 nums,返回該數(shù)組所有可能的子集(冪集)。

說明:解集不能包含重復(fù)的子集。

示例:

輸入: nums = [1,2,3]

輸出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

思路

求子集問題和77.組合和131.分割回文串又不一樣了。

如果把 子集問題、組合問題、分割問題都抽象為一棵樹的話,那么組合問題和分割問題都是收集樹的葉子節(jié)點,而子集問題是找樹的所有節(jié)點!

其實子集也是一種組合問題,因為它的集合是無序的,子集{1,2} 和 子集{2,1}是一樣的。

那么既然是無序,取過的元素不會重復(fù)取,寫回溯算法的時候,for就要從startIndex開始,而不是從0開始!

有同學(xué)問了,什么時候for可以從0開始呢?

求排列問題的時候,就要從0開始,因為集合是有序的,{1, 2} 和{2, 1}是兩個集合,排列問題我們后續(xù)的文章就會講到的。

以示例中nums = [1,2,3]為例把求子集抽象為樹型結(jié)構(gòu),如下:

子集

從圖中紅線部分,可以看出遍歷這個樹的時候,把所有節(jié)點都記錄下來,就是要求的子集集合。

回溯三部曲

  • 遞歸函數(shù)參數(shù)

全局變量數(shù)組path為子集收集元素,二維數(shù)組result存放子集組合。(也可以放到遞歸函數(shù)參數(shù)里)

遞歸函數(shù)參數(shù)在上面講到了,需要startIndex。

代碼如下:

  1. vector<vector<int>> result; 
  2. vector<int> path; 
  3. void backtracking(vector<int>& nums, int startIndex) { 

遞歸終止條件

從圖中可以看出:

子集

剩余集合為空的時候,就是葉子節(jié)點。

那么什么時候剩余集合為空呢?

就是startIndex已經(jīng)大于數(shù)組的長度了,就終止了,因為沒有元素可取了,代碼如下:

  1. if (startIndex >= nums.size()) { 
  2.     return

其實可以不需要加終止條件,因為startIndex >= nums.size(),本層for循環(huán)本來也結(jié)束了。

  • 單層搜索邏輯

求取子集問題,不需要任何剪枝!因為子集就是要遍歷整棵樹。

那么單層遞歸邏輯代碼如下:

  1. for (int i = startIndex; i < nums.size(); i++) { 
  2.     path.push_back(nums[i]);    // 子集收集元素 
  3.     backtracking(nums, i + 1);  // 注意從i+1開始,元素不重復(fù)取 
  4.     path.pop_back();            // 回溯 

C++代碼

根據(jù)關(guān)于回溯算法,你該了解這些!給出的回溯算法模板:

  1. void backtracking(參數(shù)) { 
  2.     if (終止條件) { 
  3.         存放結(jié)果; 
  4.         return
  5.     } 
  6.  
  7.     for (選擇:本層集合中元素(樹中節(jié)點孩子的數(shù)量就是集合的大小)) { 
  8.         處理節(jié)點; 
  9.         backtracking(路徑,選擇列表); // 遞歸 
  10.         回溯,撤銷處理結(jié)果 
  11.     } 

可以寫出如下回溯算法C++代碼:

  1. class Solution { 
  2. private: 
  3.     vector<vector<int>> result; 
  4.     vector<int> path; 
  5.     void backtracking(vector<int>& nums, int startIndex) { 
  6.         result.push_back(path); // 收集子集,要放在終止添加的上面,否則會漏掉自己 
  7.         if (startIndex >= nums.size()) { // 終止條件可以不加 
  8.             return
  9.         } 
  10.         for (int i = startIndex; i < nums.size(); i++) { 
  11.             path.push_back(nums[i]); 
  12.             backtracking(nums, i + 1); 
  13.             path.pop_back(); 
  14.         } 
  15.     } 
  16. public
  17.     vector<vector<int>> subsets(vector<int>& nums) { 
  18.         result.clear(); 
  19.         path.clear(); 
  20.         backtracking(nums, 0); 
  21.         return result; 
  22.     } 
  23. }; 

在注釋中,可以發(fā)現(xiàn)可以不寫終止條件,因為本來我們就要遍歷整顆樹。

有的同學(xué)可能擔(dān)心不寫終止條件會不會無限遞歸?

并不會,因為每次遞歸的下一層就是從i+1開始的。

本文轉(zhuǎn)載自微信公眾號「代碼隨想錄」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系代碼隨想錄公眾號。

 

責(zé)任編輯:武曉燕 來源: 代碼隨想錄
相關(guān)推薦

2021-10-08 11:13:41

子集問題數(shù)據(jù)結(jié)構(gòu)算法

2014-01-22 09:17:12

2024-05-28 09:12:10

2024-04-07 00:00:00

ESlint命令變量

2023-12-12 08:41:01

2023-12-20 08:23:53

NIO組件非阻塞

2024-04-30 09:02:48

2023-04-26 10:21:04

2016-03-18 19:03:35

認(rèn)知計算IBM

2021-10-14 06:52:47

算法校驗碼結(jié)構(gòu)

2022-11-04 14:16:05

2024-09-18 07:00:00

消息隊列中間件消息隊列

2025-02-18 08:11:17

2023-03-21 07:39:51

CentOS掛載硬盤

2022-12-02 14:12:52

新能源汽車海爾

2023-01-13 17:02:10

操作系統(tǒng)鴻蒙

2020-02-20 08:30:49

OSPF網(wǎng)絡(luò)協(xié)議路由協(xié)議

2022-11-28 00:04:17

2024-07-08 00:00:01

多線程ThreadC#

2022-09-29 15:32:58

云計算計算模式
點贊
收藏

51CTO技術(shù)棧公眾號