算法训练day22 | php | 93.复原IP地址 , 78.子集 , 90.子集II

一、力扣题93. 复原 IP 地址

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245""192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

示例 1:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:

输入:s = "0000"
输出:["0.0.0.0"]

示例 3:

输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

提示:

  • 1 <= s.length <= 20
  • s 仅由数字组成

        本题和上一天的分割回文串的题目逻辑差不多,同样是切割出整数 和 判断该整数是否符合ip地址的条件。

        判断整数是否符合条件有两种不符合的情况,一是整数 > 255, 二是整数不是0,且以 0 开头。

        而切割过程中,因为规定了整数的位数,所以只能循环切割出个位数,两位数,三位数。这其中就出现了一种特殊情况,当切割第四个整数时,字符串中只剩下 " 1",但此时按位数切割,解集中就会出现三个相同结果,因为切割出两位数三位数时,因为字符串只剩下 1 个数,所以最后也只切割出个位数。所以切割完后,需要判断切割后的总位数是否大于字符串长度,大于则舍弃。

class Solution {
    private $result = [];
    /**
     * @param String $s
     * @return String[]
     */
    function restoreIpAddresses($s) {
        $this->backtracking($s, "", 0, 0);
        return $this->result;
    }

    function backtracking($s, $path, $cur, $num) {
        if($num == 3) {
            if($cur >= strlen($s)) {
                $this->result[] = $path;
            }
            return;
        }
        if($path != "") {
            $path .= ".";
            $num++;
        }

        for($i = 1; $i <= 3; $i++) {
            $string = substr($s, $cur, $i);
            if($this->judge($string)) {
                if(($cur + $i) > strlen($s)) continue;
                $this->backtracking($s, $path.$string, $cur + $i, $num);
            }
        }
    }

    function judge($string) {
        if(($string[0] == "0" && isset($string[1])) || intval($string) > 255) {
            return false;
        }
        return true;
    }
}

二、力扣题78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

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

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

         本题很简单,没有什么困难点,按照回溯模板写就好辽。唯一不同的一点是,因为求的是子集,所以每次循环遍历都要把路径 path 放入结果集。

class Solution {
    private $result = [];
    /**
     * @param Integer[] $nums
     * @return Integer[][]
     */
    function subsets($nums) {
        $this->result[] = [];
        $this->backtracking($nums, [], 0);
        return $this->result;
    }

    function backtracking($nums, $path, $cur) {
        for($i = $cur; $i < count($nums); $i++) {
            $path[] = $nums[$i];
            $this->result[] = $path;
            $this->backtracking($nums, $path, $i + 1);
            array_pop($path);
        }
    }
}

三、力扣题90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

         本题与上一题的不同在于给的数组中存在重复元素,所以需要去重。

        梳理一下,同样是同一树层中不允许选取重复元素,同一树枝上可以选取重复元素,是和之前的 "组合总和II" 题目一样的套路。

        当然同样不能忘记要先排序数组。

class Solution {
    private $result = [];
    /**
     * @param Integer[] $nums
     * @return Integer[][]
     */
    function subsetsWithDup($nums) {
        $this->result[] = [];
        sort($nums);
        $this->backtracking($nums, [], 0);
        return $this->result;
    }
    
    function backtracking($nums, $path, $cur) {
        for($i = $cur; $i < count($nums); $i++) {
            if($i > $cur && $nums[$i - 1] === $nums[$i]) {
                continue;
            }
            $path[] = $nums[$i];
            $this->result[] = $path;
            $this->backtracking($nums, $path, $i + 1);
            array_pop($path);
        }
    }
}

        使用used数组去重的代码如下:

        在这里要注意一个问题,如果在判断used[ i - 1] 是否为 false 时用了三个等号,则一定要对used[ i ] 进行定义,如果不定义的话,used[ i ]不存在,那么在遍历到 i + 1 元素时,如果 i + 1元素和 i 元素相等,此时用三个等号判断,used[ i ]是不等于false,判断就失效了。

        所以要不定义used 的每一个元素 ,要不把判断used[ i - 1]是否为false 改为用两个等号。

class Solution {
    private $result = [];
    /**
     * @param Integer[] $nums
     * @return Integer[][]
     */
    function subsetsWithDup($nums) {
        $this->result[] = [];
        sort($nums);
        $this->backtracking($nums, [], 0, []);
        return $this->result;
    }
    
    function backtracking($nums, $path, $cur, $used) {
        for($i = $cur; $i < count($nums); $i++) {
            if($nums[$i - 1] === $nums[$i] && $used[$i - 1] === false) {
                $used[$i] = false;
                continue;
            }
            $used[$i] = true;
            $path[] = $nums[$i];
            $this->result[] = $path;
            $this->backtracking($nums, $path, $i + 1, $used);
            array_pop($path);
            $used[$i] = false;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值