433. 最小基因变化

题目:

思路:

【1】可以参考  剑指 Offer II 108. 单词演变(127. 单词接龙)这篇,本质上题目是类似的,或者说差不多

代码展示:

//时间1 ms 击败 66.44%
//内存39.8 MB 击败 11.69%
class Solution {
    private Map<String, Integer> wordId = new HashMap<String, Integer>();
    private List<List<Integer>> edge = new ArrayList<List<Integer>>();
    private int nodeNum = 0;

    public int minMutation(String startGene, String endGene, String[] bank) {
        // 将给出的可以变化的序列构建成图
        for (String word : bank) {
            addEdge(word);
        }
        // 起始点也要加入
        addEdge(startGene);
        if (!wordId.containsKey(endGene)) return -1;

        int[] disBegin = new int[nodeNum];
        Arrays.fill(disBegin, Integer.MAX_VALUE);
        int beginId = wordId.get(startGene);
        disBegin[beginId] = 0;
        Queue<Integer> queBegin = new LinkedList<Integer>();
        queBegin.offer(beginId);

        int[] disEnd = new int[nodeNum];
        Arrays.fill(disEnd, Integer.MAX_VALUE);
        int endId = wordId.get(endGene);
        disEnd[endId] = 0;
        Queue<Integer> queEnd = new LinkedList<Integer>();
        queEnd.offer(endId);

        while (!queBegin.isEmpty() && !queEnd.isEmpty()) {
            int queBeginSize = queBegin.size();
            for (int i = 0; i < queBeginSize; ++i) {
                int nodeBegin = queBegin.poll();
                if (disEnd[nodeBegin] != Integer.MAX_VALUE) {
                    return (disBegin[nodeBegin] + disEnd[nodeBegin]) / 2;
                }
                for (int it : edge.get(nodeBegin)) {
                    if (disBegin[it] == Integer.MAX_VALUE) {
                        disBegin[it] = disBegin[nodeBegin] + 1;
                        queBegin.offer(it);
                    }
                }
            }

            int queEndSize = queEnd.size();
            for (int i = 0; i < queEndSize; ++i) {
                int nodeEnd = queEnd.poll();
                if (disBegin[nodeEnd] != Integer.MAX_VALUE) {
                    return (disBegin[nodeEnd] + disEnd[nodeEnd]) / 2;
                }
                for (int it : edge.get(nodeEnd)) {
                    if (disEnd[it] == Integer.MAX_VALUE) {
                        disEnd[it] = disEnd[nodeEnd] + 1;
                        queEnd.offer(it);
                    }
                }
            }
        }
        return -1;
    }

    /**
     * 假设加入的单词是AAAACCCC
     * 会将单词变更为 AAA*CCCC, *AAACCC, AAAACC*C, AA*ACCCC, AAAAC*CC, AAAACCC*, A*AACCCC, AAAA*CCCd多种情况
     * 即在list中 AAAACCCC-> {AAA*CCCC, *AAACCC, AAAACC*C, AA*ACCCC, AAAAC*CC, AAAACCC*, A*AACCCC, AAAA*CCC}
     * 而其余的类似 AAA*CCCC 也会指向 {AAAACCCC}
     *
     * 如果填入 ["AAAAACCC","AAAACCCC","AAACCCCC","AACCCCCC"] 这四个字符串
     * 那么最终结果
     * MAP = {AAC*CCCC=20, AACC*CCC=21, AACCCCCC=17, AAAAAC*C=31, AAAACC*C=7, AA*AACCC=28, A*ACCCCC=11, AAAA*CCC=5, AAA*ACCC=29, AAA*CCCC=4, AAAAA*CC=30, AAAAACC*=32, AAAAC*CC=6, AAAACCC*=8, *AACCCCC=10, AAACCCCC=9, AACCC*CC=22, AACCCCC*=24, A*AAACCC=27, AA*CCCCC=12, AAACCC*C=15, AAAC*CCC=13, AAACC*CC=14, *AAACCCC=1, AAACCCC*=16, AA*ACCCC=3, A*AACCCC=2, *AAAACCC=26, AACCCC*C=23, AAAAACCC=25, *ACCCCCC=18, AAAACCCC=0, A*CCCCCC=19}
     * 其中MAP中的value则是list的下标,下标指向的集合即是可达集合
     * LIST = [[1, 2, 3, 4, 5, 6, 7, 8], [0], [0], [0], [0, 9], [0, 25], [0], [0], [0], [10, 11, 12, 4, 13, 14, 15, 16], [9], [9], [9, 17], [9], [9], [9], [9], [18, 19, 12, 20, 21, 22, 23, 24], [17], [17], [17], [17], [17], [17], [17], [26, 27, 28, 29, 5, 30, 31, 32], [25], [25], [25], [25], [25], [25], [25]]
     * @param word 构建成图的单词
     */
    public void addEdge(String word) {
        // 将这个单词加入
        addWord(word);
        int id1 = wordId.get(word);
        char[] array = word.toCharArray();
        for (int i = 0; i < array.length; ++i) {
            char tmp = array[i];
            array[i] = '*';
            String newWord = new String(array);
            addWord(newWord);
            int id2 = wordId.get(newWord);
            edge.get(id1).add(id2);
            edge.get(id2).add(id1);
            array[i] = tmp;
        }
    }

    /**
     * 塞入到MAP中,记录在list里面的下标
     * 先通过MAP判断在不在,再找出可以指向的集合
     * @param word 加入的单词
     */
    public void addWord(String word) {
        if (!wordId.containsKey(word)) {
            wordId.put(word, nodeNum++);
            edge.add(new ArrayList<Integer>());
        }
    }
}

// 更加快速的版本
//时间0 ms 击败 100%
//内存39.3 MB 击败 86.79%
class Solution {
    public int minMutation(String startGene, String endGene, String[] bank) {
        Queue<String> q=new LinkedList<>();
        HashSet<String> set=new HashSet<>();
        q.offer(startGene);
        int m=1;
        while(!q.isEmpty()){
            int size=q.size();
            for(int i=0;i<size;i++){
                String qq=q.poll();
                List<String> list=replace(qq,bank);
                if(list.size()!=0){
                    for(String s:list){
                        if(!set.contains(s)){
                            if(s.equals(endGene)) return m;
                        q.offer(s);
                        set.add(s);
                        }
                    }
                }
            }
            m++; 
        }
        return -1;
    }
    
    public List<String> replace(String x,String[] bank){
        List<String> res=new ArrayList<String>();
        for(String b:bank){
            int r=0;
            for(int i=0;i<x.length();i++){
                if(x.charAt(i)!=b.charAt(i)) r++;
            }
            if(r==1) res.add(b);
        }
        return res;
    }
}

 

posted @ 2023-07-13 12:22  忧愁的chafry  阅读(19)  评论(0)    收藏  举报