代碼隨想錄算法訓(xùn)練營第24天 | 93.復(fù)原IP地址恐锦、78.子集融击、90.子集II

93.復(fù)原IP地址

題目鏈接/文章講解

思路

cr:代碼隨想錄

  • 本題需要額外處理,需要判斷這個字串是否合法

偽代碼

//全局變量 result
 private List<String> result = new ArrayList<>(); // 記錄結(jié)果

// startIndex: 搜索的起始位置桨啃,pointNum:添加逗點的數(shù)量
    private void backtracking(StringBuilder s, int startIndex, int pointNum) {
    if (pointNum == 3) { // 逗點數(shù)量為3時车胡,分隔結(jié)束
        // 判斷第四段子字符串是否合法,如果合法就放進(jìn)result中
        if (isValid(s.toString(), startIndex, s.length() - 1)) {
            result.add(s.toString());
        }
        return;
    }
    for (int i = startIndex; i < s.length(); i++) {
          if (isValid(s.toString(), startIndex, i)) { // 判斷 [startIndex,i] 這個區(qū)間的子串是否合法
              s.insert(i + 1, '.'); // 在i的后面插入一個逗點
              pointNum++;
              backtracking(s, i + 2, pointNum); // 插入逗點之后下一個子串的起始位置為i+2
              pointNum--; // 回溯
              s.deleteCharAt(i + 1); // 回溯刪掉逗點
          } else {
              break; // 不合法照瘾,直接結(jié)束本層循環(huán)
          }
      }
}

// 判斷字符串s在左閉右閉區(qū)間[start, end]所組成的數(shù)字是否合法
    private boolean isValid(String s, int start, int end) {
        if (start > end) { //檢查子串是否為空匈棘。
            return false;
        }
        if (s.charAt(start) == '0' && start != end) { // 0開頭的數(shù)字不合法
            return false;
        }
        int num = 0;
        for (int i = start; i <= end; i++) {
            if (s.charAt(i) > '9' || s.charAt(i) < '0') { // 遇到非數(shù)字字符不合法
                return false;
            }
            //  將字符串形式的數(shù)字轉(zhuǎn)換為整數(shù)形式
            num = num * 10 + (s.charAt(i) - '0');
            if (num > 255) { // 如果大于255了不合法
                return false;
            }
        }
        return true;
    }
public List<String> restoreIpAddresses(String s) {
        result.clear();
        if (s.length() < 4 || s.length() > 12) return result; // 剪枝
        backtracking(new StringBuilder(s), 0, 0);
        return result;
    }

class Solution {
    private List<String> result = new ArrayList<>();
    private void backtracking(StringBuilder s, int startIndex, int dotNum){
        if(dotNum == 3) {
            if(isValid(s.toString(), startIndex, s.length()-1)){
                result.add(s.toString());
            }
            return;
        }
        for(int i = startIndex; i < s.length(); i++){
            if(isValid(s.toString(), startIndex, i)){
                s.insert(i+1, '.');
                dotNum++;
                backtracking(s, i+2, dotNum);
                dotNum--;
                s.deleteCharAt(i+1);
            }else{
                break;
            }
        }

    }
    private boolean isValid(String s, int start, int end) {
        if(start > end) return false;
        //if(s.charAt(start) == '0' && s.charAt(start) != s.charAt(end)) return false; //這里不能這樣寫
        if(s.charAt(start) == '0' && start != end) return false;
        int num = 0;
        for(int i = start; i <= end; i++){ //注意這里是start和end
            if(s.charAt(i) > '9' || s.charAt(i) < '0') return false; //注意這里比較的是char
            num = num * 10 + (s.charAt(i) - '0');
            if(num > 255) return false;
        }
        return true;
       
    }

    public List<String> restoreIpAddresses(String s) {
        result.clear();
        if(s.length() > 12 || s.length() < 4) return result;
        backtracking(new StringBuilder(s), 0, 0);
        return result;
    }
}

78.子集

題目鏈接/文章講解
子集問題,就是收集樹形結(jié)構(gòu)中析命,每一個節(jié)點的結(jié)果主卫。 整體代碼其實和 回溯模板都是差不多的逃默。

思路

cr:代碼隨想錄

  • 每一個子集都是一個組合
class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private List<Integer> path = new ArrayList<>();

    private void backtracking(int[] nums, int startIndex) {
        result.add(new ArrayList<>(path)); // 收集子集,要放在終止添加的上面簇搅,否則會漏掉自己

        // 終止條件可以不加完域,因為startIndex >= nums.length,本層for循環(huán)本來也結(jié)束了
        if (startIndex >= nums.length) {
            return;
        }

        for (int i = startIndex; i < nums.length; i++) {
            path.add(nums[i]);
            backtracking(nums, i + 1); // 注意從i+1開始瘩将,元素不重復(fù)取吟税。比如取了(1,2)就沒有必要取(2,1)
            path.remove(path.size() - 1); // 回溯
        }
    }

    public List<List<Integer>> subsets(int[] nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = {1, 2, 3};
        List<List<Integer>> subsets = solution.subsets(nums);
        System.out.println(subsets); // 輸出子集組合
    }
}
class Solution {
    private List<Integer> path = new ArrayList<>();
    private List<List<Integer>> result = new ArrayList<>();
    private void backtracking(int[] nums, int startIndex){  //這里一開始居然忘寫返回值了姿现。肠仪。。备典。
        result.add(new ArrayList<>(path));
        if(startIndex > nums.length) return;
        for(int i = startIndex; i < nums.length; i++){
            path.add(nums[i]);
            backtracking(nums, i+1);
            path.remove(path.size() - 1);
        }
    }
    public List<List<Integer>> subsets(int[] nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }
}

90.子集II

題目鏈接/文章講解
大家之前做了 40.組合總和II 和 78.子集 异旧,本題就是這兩道題目的結(jié)合,建議自己獨立做一做提佣,本題涉及的知識吮蛹,之前都講過,沒有新內(nèi)容拌屏。

思路

  • 本題中可以有重復(fù)元素潮针,所以有去重操作


    image.png

使用 used 數(shù)組來去重的版本

class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private List<Integer> path = new ArrayList<>();

    private void backtracking(int[] nums, int startIndex, boolean[] used) {
        result.add(new ArrayList<>(path));
        for (int i = startIndex; i < nums.length; i++) {
            // used[i - 1] == true,說明同一樹枝 nums[i - 1] 使用過
            // used[i - 1] == false倚喂,說明同一樹層 nums[i - 1] 使用過
            // 而我們要對同一樹層使用過的元素進(jìn)行跳過
            if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            backtracking(nums, i + 1, used);
            used[i] = false;
            path.remove(path.size() - 1);
        }
    }

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        result.clear();
        path.clear();
        boolean[] used = new boolean[nums.length];
        Arrays.sort(nums); // 去重需要排序
        backtracking(nums, 0, used);
        return result;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = {1, 2, 2};
        List<List<Integer>> subsets = solution.subsetsWithDup(nums);
        System.out.println(subsets); // 輸出子集組合
    }
}

不使用 used 數(shù)組來去重的版本
i 是當(dāng)前考慮的元素的索引然低,startIndex 是當(dāng)前遞歸層的起始索引。檢查 nums[i] == nums[i - 1] 可以檢測當(dāng)前元素是否與前一個元素相同务唐。結(jié)合 i > startIndex,可以確保這種比較只在同一層級內(nèi)進(jìn)行带兜。

class Solution {
    private List<List<Integer>> result = new ArrayList<>();
    private List<Integer> path = new ArrayList<>();

    private void backtracking(int[] nums, int startIndex) {
        result.add(new ArrayList<>(path));
        for (int i = startIndex; i < nums.length; i++) {
            // 而我們要對同一樹層使用過的元素進(jìn)行跳過
            if (i > startIndex && nums[i] == nums[i - 1]) { // 注意這里使用 i > startIndex
                continue;
            }
            path.add(nums[i]);
            backtracking(nums, i + 1);
            path.remove(path.size() - 1);
        }
    }

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        result.clear();
        path.clear();
        Arrays.sort(nums); // 去重需要排序
        backtracking(nums, 0);
        return result;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枫笛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子刚照,更是在濱河造成了極大的恐慌刑巧,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件无畔,死亡現(xiàn)場離奇詭異啊楚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)浑彰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門恭理,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人郭变,你說我怎么就攤上這事颜价⊙谋#” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵周伦,是天一觀的道長夕春。 經(jīng)常有香客問我,道長专挪,這世上最難降的妖魔是什么及志? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮寨腔,結(jié)果婚禮上速侈,老公的妹妹穿的比我還像新娘。我一直安慰自己脆侮,他們只是感情好锌畸,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著靖避,像睡著了一般潭枣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幻捏,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天盆犁,我揣著相機(jī)與錄音,去河邊找鬼篡九。 笑死谐岁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的榛臼。 我是一名探鬼主播伊佃,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沛善!你這毒婦竟也來了航揉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤金刁,失蹤者是張志新(化名)和其女友劉穎帅涂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尤蛮,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡媳友,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了产捞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片醇锚。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坯临,靈堂內(nèi)的尸體忽然破棺而出搂抒,到底是詐尸還是另有隱情艇搀,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布求晶,位于F島的核電站焰雕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏芳杏。R本人自食惡果不足惜矩屁,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爵赵。 院中可真熱鬧吝秕,春花似錦、人聲如沸空幻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秕铛。三九已至约郁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間但两,已是汗流浹背鬓梅。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留谨湘,地道東北人绽快。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像紧阔,于是被迫代替她去往敵國和親坊罢。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容