概述
753. 破解保险箱
有一个需要密码才能打开的保险箱。密码是 n 位数, 密码的每一位是 k 位序列 0, 1, ..., k-1 中的一个 。
你可以随意输入密码,保险箱会自动记住最后 n 位输入,如果匹配,则能够打开保险箱。
举个例子,假设密码是 "345",你可以输入 "012345" 来打开它,只是你输入了 6 个字符.
请返回一个能打开保险箱的最短字符串。
示例1:
输入: n = 1, k = 2
输出: "01"
说明: "10"也可以打开保险箱。
示例2:
输入: n = 2, k = 2
输出: "00110"
说明: "01100", "10011", "11001" 也能打开保险箱。
提示:
n 的范围是 [1, 4]。
k 的范围是 [1, 10]。
k^n 最大可能为 4096。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/cracking-the-safe
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
做题结果
失败,就觉得没思路,好像难以穷举所有结果,那如果走到错误的结果,怎么退回来?如何确定完成所有枚举结果?这几个问题没搞清楚。
方法:DFS
1. 所有值都当做10进制看待(因为最多只有4位,不会超范围)
2. 必然存在回路,走一条边之后,一定有一种方法可以回到起点。所以解决了退回来的问题。一定会回来,不用退。
3. 回到起点后,可能存在另一个没走过的回路,继续走直到完成所有回路。解决了第二个问题,走完所有可以走的路就能枚举出所有结果。
class Solution {
int k;
boolean []existed;
StringBuilder sb = new StringBuilder();
int last;
public String crackSafe(int n, int k) {//长度,数位最大+1
last = (int) Math.pow(10,n-1);
existed = new boolean[last*10];
this.k = k;
dfs(0);
for(int i = 1; i < n; i++){
sb.append("0");
}
return sb.toString();
}
private void dfs(int v){
for(int i = 0; i < k; i++){
int next = v*10+i;
if(!existed[next]){
existed[next] = true;
dfs(next%last);
sb.append(i);
}
}
}
}
感想
别管题目多难,还是要敢写,不行就贪心或者暴力,试过了才不会有遗憾。
332.重新安排行程 回溯
给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
例如,行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。示例 1:
输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
输出:["JFK","MUC","LHR","SFO","SJC"]
示例 2:
输入:tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
输出:["JFK","ATL","JFK","SFO","ATL","SFO"]
解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ,但是它字典排序更大更靠后。提示:
1 <= tickets.length <= 300
tickets[i].length == 2
fromi.length == 3
toi.length == 3
fromi 和 toi 由大写英文字母组成
fromi != toi来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reconstruct-itinerary
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
做题结果
成功,就是回溯,很简单,这题放现在应该算中等吧?
方法:DFS 暴搜
1. 建立图
2. 每个节点行程对应字典排序
3. 所有票都用完,得到可行结果
4. 每次乘飞机过程,消耗一张票(删除图的边,因为对于一个可行解来说用掉的票不能再用),如果不是可行结果,把票退回来(添加图的边)
5. 如果图中空了,没节点了,说明走完了,发现可行解,进行返回
6. 由于所有方案都是先走的字典序小的,所以遇到可行结果直接返回即可
7. 优化:如果从当前选择继续走可找到可行解,后续其他选择无需再走
class Solution {
public List<String> findItinerary(List<List<String>> tickets) {
Map<String,List<String>> graph = new HashMap<>();
for(List<String> ticket:tickets){
graph.putIfAbsent(ticket.get(0),new ArrayList<>());
graph.get(ticket.get(0)).add(ticket.get(1));
}
for(String key:graph.keySet()){
Collections.sort(graph.get(key));
}
List<String> curr = new ArrayList<>();
curr.add("JFK");
dfs(graph,"JFK",curr);
return ans;
}
List<String> ans = new ArrayList<>();
private boolean dfs(Map<String,List<String>> graph, String key,List<String> curr){
if(graph.isEmpty()) {
ans = new ArrayList<>(curr);
return true;
}
if(graph.get(key)==null) return false;
List<String> next = new ArrayList<>(graph.get(key));
int n = next.size();
for(int i = 0; i < n; i++){
String nex = next.get(i);
graph.get(key).remove(i);
if(graph.get(key).isEmpty()) graph.remove(key);
curr.add(nex);
if(dfs(graph,nex,curr))return true;
curr.remove(curr.size()-1);
graph.putIfAbsent(key,new ArrayList<>());
graph.get(key).add(i,nex);
}
return false;
}
}
最后
以上就是柔弱菠萝为你收集整理的753. 破解保险箱 DFS+332.重新安排行程 回溯753. 破解保险箱332.重新安排行程 回溯的全部内容,希望文章能够帮你解决753. 破解保险箱 DFS+332.重新安排行程 回溯753. 破解保险箱332.重新安排行程 回溯所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复