剑指 Offer II 109. 开密码锁-BFS-Java

1.题目

 

2.思路

一开始想着能不能先使用DFS,快速写出来,然后再使用BFS来写,因为一般DFS写代码的时间短一点,BFS 需要自己构建队列,时间会长一点。

然后DFS超时了,因为DFS侧重于遍历从起点到最深的节点,相当于这里会遍历无数个没用的节点。时间复杂度应该是O(10 ^ 4 * 10 ^ 4),所以只能用BFS来判断。

对于BFS来说,每一次遍历都是一层,相当于是走一步,这样总会有x层的时候,走到target,找到答案,或者结束。

这道题的两个要点:

  • 如何求解一个字符串的下一个字符串?比如一开始为“0000”,下一个字符串有哪些?
  • 注意边界条件剪枝,比如记录是否访问过vis, 是不是出现在死亡数组里面。

第一个问题求解一个字符串的下一个字符串?

首先就是有四个字符可以进行+ 1 和 -1 两个操作,所以相当于有8个候选字符串。每次从中选一个假如队列即可。中间会有一些已经访问过的,所以记得去重剪枝,不然会超时。

注意字符串数组char[]arr转化为String的话,不要用arr.toString(),因为这样得到的是字符串的地址。需要使用new String(arr)

可以使用一个函数来计算下一个字符串的集合。这样代码功能区分更明显。

第二个问题剪枝

  • 一开始用一个map存一下死亡数组,这样可以O(1)时间判断是否出现在死亡数组中。
  • 用一个visMap记录这个字符串是否已经访问过,剪枝
  • 最开始判断target是否出现在死亡数组里面,如果出现,直接return -1
  • 找到结果,return step

时间复杂度——O(10^4 * (8 + 8) +  4 * m)

首先,从“0000”  -- “9999”总共有10 ^ 4个字符串(状态空间的上限)。然后计算每个字符串的下一个字符为O(8), 加入队列也有O(8),然后还有计算思死亡数组的O(4 * m),大概是这样。

空间复杂度——O(10^4 * 8 + m + 1)

首先死亡数组的哈希表空间O(m), 然后队列中存的元素最大个数为10^ 4 , 每个字符串长度为4,还有一个step 1, 为O(10 * 4 + 5),大概是这样。

class Solution {
    int ans = 0;
    Map<String, Integer>map = new HashMap();
    Map<String, Integer>visMap = new HashMap();
    public int openLock(String[] deadends, String target) {
        for(String s : deadends){
            map.put(s, 1);
        }
        if(map.containsKey(target))return -1;
        Deque<String[]>d = new ArrayDeque<>();
        d.addLast(new String[]{"0000", "0"});
        while(!d.isEmpty()){
            String[]cur = d.pollFirst();
            String start = cur[0];
            int step = Integer.parseInt(cur[1]);
            if(map.containsKey(start))continue;
            if(visMap.containsKey(start))continue; //已经访问过
            if(start.equals(target)){  //找到答案
                return step;
            }
            visMap.put(start, 1);
            List<String>list = getNextString(start);
            for(String s : list){
                if(!map.containsKey(s) && !visMap.containsKey(s)){
                    d.addLast(new String[]{s, step + 1 +""});
                }
            }

        }
        return -1;
    }
    public List<String> getNextString(String s){
        char[]arrays = s.toCharArray();
        int[]dx = new int[]{1, -1};
        List<String>list = new ArrayList<String>();
        for(int i = 0 ; i < 4; i++){
            for(int j = 0 ; j < 2; j++){
                char tempCopy = arrays[i];
                int temp = (int)(arrays[i] - '0') + dx[j];
                if(temp == -1){
                    arrays[i] = '9';
                }
                else if(temp == 10){
                    arrays[i] = '0';
                }
                else{
                    arrays[i] = (char)(temp + '0');
                }
                list.add(new String(arrays));
                // list.add(arrays.toString()); //不能这样将字符数组转化为字符串。这样输出的是字符串的地址。
                arrays[i] = tempCopy;
            }
        }
        return list;
    }
}

3.结果

如果用Set存储,应该时间还会再少一些。 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值