《LeetCode之每日一题》:103.复原 IP 地址
Posted 是七喜呀!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:103.复原 IP 地址相关的知识,希望对你有一定的参考价值。
题目链接: 复原 IP 地址
有关题目
给定一个只包含数字的字符串,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 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 地址。
示例 1:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
示例 2:
输入:s = "0000"
输出:["0.0.0.0"]
示例 3:
输入:s = "1111"
输出:["1.1.1.1"]
示例 4:
输入:s = "010010"
输出:["0.10.0.10","0.100.1.0"]
示例 5:
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3",
"101.0.2.3"]
提示:
0 <= s.length <= 3000
s 仅由数字组成
题解
法一:回溯
代码一:
构建递归函数:dfs(segId,segStart)表示
我们正从s[segStart]的位置开始,搜索IP地址中的segStart段
其中segId∈{0,1,2,3}
结合题干所给ip地址每一段∈[0,255],从segStart的位置开始
,当前地址段ip的结束位置segEnd,满足条件的,我们进行递归进行下一段搜索dfs(s,segStart + 1,segEnd + 1)
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
#define SEG_COUNT 4
int segments[SEG_COUNT];
char** ans;
int ans_len;
void dfs(char *s, int segId, int segStart)
{
int len_s = strlen(s);
if (segId == SEG_COUNT)
{
// 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
if (segStart == len_s)
{
char* ipAddr = (char*)malloc((len_s + 4) * sizeof(char));
int i = 0;
for (int k = 0; k < SEG_COUNT; k++)
{
int num = segments[k];
if (num >= 100 && num <= 255) ipAddr[i++] = num / 100 + '0';
if (num >= 10 && num <= 255) ipAddr[i++] = num % 100 / 10 + '0';
ipAddr[i++] = num % 10 + '0';
if (k != SEG_COUNT - 1) ipAddr[i++] = '.';
}
ipAddr[i] = '\\0';
ans = (char**)realloc(ans,sizeof(char*) * (ans_len + 1));
ans[ans_len++] = ipAddr;
}
return ;
}
// 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
if (segStart == len_s)
return ;
// 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
if (s[segStart] == '0')
{
segments[segId] = 0;
dfs(s,segId + 1, segStart + 1);
}
// 一般情况,枚举每一种可能性并递归
int Addr = 0;
for (int segEnd = segStart; segEnd < len_s; segEnd++)
{
Addr = Addr * 10 + (s[segEnd] - '0');
if (Addr > 0 && Addr <= 255)
{
segments[segId] = Addr;
dfs(s, segId + 1, segEnd + 1);
}
else
break;
}
}
char ** restoreIpAddresses(char * s, int* returnSize){
ans = (char**)malloc(0);
ans_len = 0;
dfs(s,0,0);
*returnSize = ans_len;
return ans;
}
代码二:
class Solution {
private List<String> res;
private StringBuilder path;
private String s;
public List<String> restoreIpAddresses(String s) {
this.res = new ArrayList<>();
if (s == null || s.length() == 0) return res;
this.s = s;
path = new StringBuilder();
dfs(0, 3);
return res;
}
// start 表示截取子串的起点
// resNum 表示剩余的ip段个数
private void dfs(int start, int resNum) {
// 如果所有ip段都已经找完了,添加答案到集合中并返回
if (resNum == -1 && start == s.length()) {
// 删除最后添加的点号
path.setLength(path.length() - 1);
res.add(path.toString());
return;
}
// 如果遍历完字符串还没有找完ip,提前返回
if (start == s.length()) return;
char[] c = s.toCharArray();
int pathLen = path.length();
int len = c.length;
// 子串右边界范围必须同时满足两个条件,取范围的交集
// 1. 根据数字最多不能超过三位,最少一位得出:[start + 1, start + 3]
// 2. 根据剩余还需要拼接的ip地址个数得出:[len - 3 * resNum, len - resNum]
int max = Math.min(start + 3, len - resNum);
int min = Math.max(start + 1, len - 3 * resNum);
for (int i = min; i <= max; i++) {
// 第一个字符为0,剪支
if (i > start + 1 && c[start] == '0') break;
// 当前的数字越界,剪支
String sub = s.substring(start, i);
int num = Integer.parseInt(sub);
if (num > 255) break;
path.append(sub).append(".");
dfs(i, resNum - 1);
path.setLength(pathLen);
}
}
}
以上是关于《LeetCode之每日一题》:103.复原 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章