一、力扣题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;
}
}
}