LeetCode46全排列(回溯入門)

来源:https://www.cnblogs.com/bolingcavalry/archive/2023/09/01/17658367.html
-Advertisement-
Play Games

### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 題目描述 - 難度:中等 - 給定一個不含重覆數字的數 ...


歡迎訪問我的GitHub

這裡分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos

題目描述

  • 難度:中等

  • 給定一個不含重覆數字的數組 nums ,返回其 所有可能的全排列 。你可以 按任意順序 返回答案

  • 示例 1

輸入:nums = [1,2,3]
輸出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
  • 示例 2
輸入:nums = [0,1]
輸出:[[0,1],[1,0]]
  • 示例 3
輸入:nums = [1]
輸出:[[1]]

個人回溯和46題的理解

  • 在很多刷題文章和書籍中,此題都被用做回溯演算法的第一題,可見該題很有代表性,搞定此題意味著對回溯有了最基本的瞭解,當然就個人感受而言,以此作為回溯的第一題弊端也不小:本以為掌握了基本套路,刷其他回溯題的時候套上去即可,結果後來發下一道題都套不成功...

  • 套不成功?是因為此題沒有代表性嗎?當然不是,這是道典型的回溯演算法題,但個人的感覺是:解題的關鍵不是套用模板,而是對回溯思想的理解,我個人的理解是:深度至上

  • 所謂深度至上,就是弄清楚在當前深度能做什麼,例如46題全排列,一個深度意味著可選數字中做了一輪選擇,每選中一個,都牢牢占據這一層的固定位置,下麵的子樹都要有他

  • 只要理解了深度至上,就清楚在當前做任何事情的時候都要確保深度固定,下圖是[1,2]兩個數字全排列的手繪圖,邊上數字表示選擇,方框中的數字表示選擇後的結果,請看藍色框,在選擇2的時候,要牢記當深度只能有一個數字,於是,剛纔選擇1的時候記錄存在路徑中的1就要果斷刪除,牢記當前層應該占據哪個位置,回溯的效果就有了

image-20220724233658937

解題思路

  • 要用回溯演算法解此題,有幾個關鍵要註意

  • 全排列,意味著相同數字只要排列不同,也能算作結果的一種

  • 雖然不推薦用模板去套,但回溯該有的幾個核心概念還是不能少的:

  1. 終止條件:只要組合的數字達到給定數字的長度,就可以終止了

  2. 路徑:就是正在組合的元素,可以用數組表達

  • 此外還要有個輔助參數,用於記錄那些值不能參與組合,以上圖為例,在藍色那一層如果選擇了1,那麼在下一層就不能再選擇1了,所以在組合的時候,要有地方可以查到1不可用

編碼

  • 接下來可以寫代碼了,如下,有幾處要註意的地方稍後會提到
public class L0046 {

    List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
        // 回溯過程中的重要輔助參數:標記nums數組中有哪些已經使用過
        boolean[] used = new boolean[nums.length];
        // 回溯過程中的重要輔助參數:路徑
        int[] path = new int[nums.length];

        dfs(nums, used, path, 0);
        return res;
    }

    public void dfs(int[] nums, boolean[] used, int[] path, int depth) {
        // 終止條件(深度達到)
        // 搜集:棧入res
        // 本題的終止條件是一次組合的長度達到數組長度
        if (depth==nums.length) {
            // 搜集結果
            // 千萬註意:這個path一直在使用中,所以不能把path放入res中,而是path的元素
//            res.add(Arrays.stream(path).boxed().collect(Collectors.toList()));


            List<Integer> list = new ArrayList<>();
            for(int val : path) {
                list.add(val);
            }

            res.add(list);
            return;
        }

        // for迴圈
        for (int i=0;i<nums.length;i++) {
            // 如果當前數字沒有用到,就標記,進入path,再做dfs
            if (!used[i]) {
                used[i] = true;
                // 註意,path的下標千萬不要用i!
                // 例如1和2的全排列,在製造[2,1]的時候,i=1,但此時要修改的是path[i],
                // 所以path的下標應該是depth
                path[depth] = nums[i];
                // 一次遞歸,深度要加一
                dfs(nums, used, path, depth+1);
                used[i] = false;
            }
        }
    }

    public static void main(String[] args) {
        List<List<Integer>> list = new L0046().permute(new int[] {1,2,3});

        list.forEach(one -> {
           Tools.printOneLine(one);
        });

    }
}
  • 上述代碼有以下幾處要註意
  1. res用於搜集達到終止條件的記錄,也就是數字組合結果
  2. dfs方法就是本次回溯操作的核心方法
  3. 下圖紅色箭頭所指代碼就是本題最重要的一行,可見for迴圈的執行過程中,修改的都是path數組的同一個位置的值,這就是剛纔提到的深度至上,只有進入了下麵的dfs方法後,深度變化,修改的path數組的位置才會發生變化

image-20220724234403151

  1. used數組用來記錄深度調用過程中,那些數字已經被使用了,當前不要再使用
  2. 很多回溯的代碼中,用棧對象保持path中的數據,入棧push,出棧pop都是標準操作,但是本題中用char數組,再配合depth,就可以滿足需要了,這種原始類型的使用也會帶來更好的性能

執行結果

  • 寫完代碼提交,執行結果如下,超過100.00%的提交

image-20220724235026851

  • 至此,回溯入門實戰已經完成,此時需要強烈提示:代碼中那個for迴圈,在每一層都遍歷nums的所有元素,那是此題的特殊操作,千萬不要以為是模板或者套路,其他回溯題中,不會像此題這樣每一層都遍歷的

歡迎關註博客園:程式員欣宸

學習路上,你不孤單,欣宸原創一路相伴...


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ![file](https://img2023.cnblogs.com/other/3195851/202308/3195851-20230831114702799-1091292653.jpg) 提到數據處理,經常有人把它簡稱為“ETL”。但仔細說來,數據處理經歷了ETL、ELT、XX ETL(例 ...
  • ![file](https://img2023.cnblogs.com/other/2685289/202308/2685289-20230831101757216-1368442529.png) 作者 | 李晨 編輯 | Debra Chen 數據準備對於推動有效的自助式分析和數據科學實踐至關重要 ...
  • 一、尋找合適的線上預覽Excel的js庫 我: 線上預覽Excel文件有哪些好用的js庫 ChatGPT: 有幾個好用的JavaScript庫可以用來在網頁上實現線上預覽Excel文件。以下是一些常見且功能強大的庫: SheetJS (xlsx.js): 這是一個功能強大的庫,可以在網頁上實現Exc ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 問題描述:最近工作中出現一個需求,純前端下載 Excel 數據,並且有的下載內容很多,這時需要給下載增加一個 loading 效果。 代碼如下: // utils.js const XLSX = require('xlsx') // 將一 ...
  • # React Native 封裝Toast ## 前言 > 使用react native的小伙伴都知道,官方並未提供輕提示組件,只提供了ToastAndroid API,顧名思義,只能再安卓環境下使用,對於ios就愛莫能助,故此,只能通過官方的核心組件,自行封裝,實現Toast功能 ## 實現 * ...
  • 本文主要介紹 AI 繪圖開源工具 Stable Diffusion WebUI 的 API 開啟和基本調用方法,通過本文的閱讀,你將瞭解到 stable-diffusion-webui 的基本介紹、安裝及 API 環境配置;文生圖、圖生圖、局部重繪、後期處理等 API 介面調用;圖像處理開發中常用到... ...
  • 今天給大家介紹下掃碼登錄功能是怎麼設計的。 掃碼登錄功能主要分為三個階段:待掃描、已掃描待確認、已確認。 整體流程圖如圖。 下麵分階段來看看設計原理。 1、待掃描階段 首先是待掃描階段,這個階段是 PC 端跟服務端的交互過程。 每次用戶打開PC端登陸請求,系統返回一個唯一的二維碼ID,並將二維碼ID ...
  • 前言 前面說了很多Kafka的性能優點,有些童鞋要說了,這Kafka在企業開發或者企業級應用中要怎麼用呢?今天咱們就來簡單探究一下。 1、 使用 Kafka 進行消息的非同步處理 Kafka 提供了一個可靠的消息傳遞機制,使得企業能夠將不同組件之間的通信解耦,實現高效的非同步處理。在企業級應用中,可以通 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...