写在前面
中概惨,美团最近更是惨上加惨。
利润率个位数,财报爆雷,现在还被谣言击穿防线,造成单日 <math xmlns="http://www.w3.org/1998/Math/MathML"> 5 5 </math>5 个点以上的跌幅。
自从字节的现象级产品 抖音 做出流量后,往各个方向扩张的脚步就从未停下。
其中就包括对涵盖"线下消费"一条龙的 美团 的围剿。
最近网传: 抖音要收购阿里的饿了么。
该消息现在已被抖音官方辟谣,但这个消息能够流传开来,是有它的逻辑的。
除了是 字节跳动一贯的围剿风格。
另一方面,是 阿里巴巴目前在收缩战线,最近不断出售前期投资项目的股期股权。
因此,对于出售饿了么,资本持基本相信态度。
对于美团,目前没有太好的破局思路。
国内几乎所有互联网,流量虽大,但几乎没有什么核心护城河。
美团能做的东西,抖音也能做,但光靠那 20%-30% 的用户体验差别,是不足以让这"第一名"的头衔易主的。
消费者/用户的心智空间,通常只会记住第一名,只要不发生实际上的区别,第一名会永远的赢下去。
美团目前能做的,就是熬到字节跳动没有耐心,最终放弃围剿。
毕竟字节跳动的围剿也是有成本次数限制的。
无论是"对教培的围剿"(政策)、"对游戏的围剿"、或是"对 SHEIN 的围剿"目前都几乎接近尾声。
美团只能把希望放在,抖音会放弃对「线下业务」的围剿。
这是一个合理的期望,毕竟抖音的流量有更好的变现方式,单纯为了搞垮美团而无底线的违背经济原则是不可持续的。
剩者为王,美团只能重新和抖音,再走一次当时和点评走过的路。
闲话聊完了,回归主线,咱可是算法区博主,来一道美团笔试面试真题。
题目描述
平台:LeetCode
题号:93
有效 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:
ini
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
示例 2:
ini
输入:s = "0000"
输出:["0.0.0.0"]
提示:
- <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = s . l e n g t h < = 20 1 <= s.length <= 20 </math>1<=s.length<=20
s
仅由数字组成
回溯算法
一道求所有方案的题目,只能是没有太多优化的「爆搜」做法。
设计递归函数 void dfs(int idx, int n, List<Integer> cur)
,其中 idx
代表当前处理字符串 s
的哪个位置,n
代表字符串 s
总长度,而 cur
的则是代表子串 <math xmlns="http://www.w3.org/1998/Math/MathML"> s [ 0... ( i d x − 1 ) ] s[0 ... (idx - 1)] </math>s[0...(idx−1)] 部分的具体划分方案。
用题目样例 s = "25525511135"
作为 🌰,n
固定为 11
。
当 idx = 3
时,cur
为 <math xmlns="http://www.w3.org/1998/Math/MathML"> s [ 0...2 ] = 255 s[0...2] = 255 </math>s[0...2]=255,cur
部分的划分方案可能是 [2,5,5]
、[2,55]
、[25,5]
、[255]
之一。
在 cur
的基础上,我们继续爆搜剩余部分,即递归执行 dfs(idx, n, cur)
,算法会将剩余部分的划分方案添加到 cur
上,我们只需要确保每次追加到 cur
的数值符合要求即可(没有前导零 且 范围在 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ 0 , 255 ] [0, 255] </math>[0,255] 中)。
在单次回溯过程中,我们可以将 idx
作为当前划分数字的左端点,通过枚举的形式找到右端点 j
,并将当前数字 <math xmlns="http://www.w3.org/1998/Math/MathML"> s [ i d x . . . ( j − 1 ) ] s[idx ... (j - 1)] </math>s[idx...(j−1)] 加到 cur
中(若合法),回溯到底后再添加到 cur
的元素进行移除。
当 idx = n
代表整个 s
已经处理完成,若此时 cur
恰好有 <math xmlns="http://www.w3.org/1998/Math/MathML"> 4 4 </math>4 个元素,说明我们找到了一组合法方案,将其拼接成字符串追加到答案数组中。
同时也是由于划分过程中 cur
最多只有 <math xmlns="http://www.w3.org/1998/Math/MathML"> 4 4 </math>4 个元素,我们可以用此做简单剪枝。
Java 代码:
Java
class Solution {
List<String> ans = new ArrayList<>();
char[] cs;
public List<String> restoreIpAddresses(String s) {
cs = s.toCharArray();
dfs(0, cs.length, new ArrayList<>());
return ans;
}
void dfs(int idx, int n, List<Integer> cur) {
if (cur.size() > 4) return ;
if (idx == n) {
if (cur.size() == 4) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 4; i++) sb.append(cur.get(i)).append(".");
ans.add(sb.substring(0, sb.length() - 1));
}
} else {
for (int i = idx; i < n; i++) {
int t = 0;
for (int j = idx; j <= i; j++) t = t * 10 + (cs[j] - '0');
if (cs[idx] == '0' && i != idx) break;
if (t > 255) break;
cur.add(t);
dfs(i + 1, n, cur);
cur.remove(cur.size() - 1);
}
}
}
}
C++ 代码:
C++
class Solution {
public:
vector<string> ans;
string s;
void dfs(int idx, int n, vector<int>& cur) {
if (cur.size() > 4) return ;
if (idx == n) {
if (cur.size() == 4) {
string sb;
for (int i = 0; i < 4; i++) sb += to_string(cur[i]) + ".";
ans.push_back(sb.substr(0, sb.length() - 1));
}
} else {
for (int i = idx; i < n; i++) {
int t = 0;
for (int j = idx; j <= i; j++) t = t * 10 + (s[j] - '0');
if (s[idx] == '0' && i != idx) break;
if (t > 255) break;
cur.push_back(t);
dfs(i + 1, n, cur);
cur.pop_back();
}
}
}
vector<string> restoreIpAddresses(string _s) {
s = _s;
vector<int> cur;
dfs(0, s.length(), cur);
return ans;
}
};
Python 代码:
Python
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
ans = []
def dfs(idx, n, cur):
if len(cur) > 4:
return
if idx == n:
if len(cur) == 4:
ans.append('.'.join(cur))
else:
for i in range(idx, n):
t = 0
for j in range(idx, i + 1):
t = t * 10 + (ord(s[j]) - ord('0'))
if s[idx] == '0' and i != idx:
break
if t > 255:
break
cur.append(str(t))
dfs(i + 1, n, cur)
cur.pop()
dfs(0, len(s), [])
return ans
TypeScript 代码:
TypeScript
function restoreIpAddresses(s: string): string[] {
const ans = new Array<string>()
function dfs(idx: number, n: number, cur: Array<number>): void {
if (cur.length > 4) return
if (idx == n) {
if (cur.length == 4) {
let str = ''
for (let i = 0; i < 4; i++) str += cur[i] + "."
ans.push(str.substring(0, str.length - 1))
}
} else {
for (let i = idx; i < n; i++) {
let t = 0
for (let j = idx; j <= i; j++) t = t * 10 + (s.charCodeAt(j) - '0'.charCodeAt(0))
if (s[idx] == '0' && i != idx) break
if (t > 255) break
cur.push(t)
dfs(i + 1, n, cur)
cur.pop()
}
}
}
dfs(0, s.length, new Array<number>())
return ans
}
- 时间复杂度:爆搜不讨论时空复杂度
- 空间复杂度:爆搜不讨论时空复杂度
更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉