广度优先搜索和深度优先搜索

子集

lintcode-17
解法1:组合型DFS

public class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> subsets = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        subsetHelper(nums, 0, new ArrayList<Integer>(), subsets);
        return subsets;
    }

    public void subsetHelper(int[] a, int start, List<Integer> subset, List<List<Integer>> subsets) {
        subsets.add(new ArrayList<Integer>(subset));
        for (int i = start; i < a.length; ++i) {
            subset.add(a[i]);
            subsetHelper(a, i + 1, subset, subsets);
            subset.remove(subset.size() - 1);
        }
    }
}

解法2:BFS

public class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> subsets = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        Queue<List<Integer>> queue = new ArrayDeque<List<Integer>>();
        queue.offer(new ArrayList<Integer>());
        while (!queue.isEmpty()) {
            List<Integer> subset = queue.poll();
            subsets.add(new ArrayList<Integer>(subset));
            for (int i = 0; i < nums.length; ++i) {
                if (subset.size() > 0 && subset.get(subset.size() - 1) >= nums[i]) {
                    continue;
                }
                subset.add(nums[i]);
                queue.offer(new ArrayList<Integer>(subset));
                subset.remove(subset.size() - 1);
            }
        }
        return subsets;
    }
}

相似题目:子集II
lintcode-18
解法1:组合型DFS+剪枝

public class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> subsets = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        subsetHelper(nums, 0, new ArrayList<Integer>(), subsets);
        return subsets;
    }

    public void subsetHelper(int[] a, int start, List<Integer> subset, List<List<Integer>> subsets) {
        subsets.add(new ArrayList<Integer>(subset));
        memo.add(serialize(subset));
        for (int i = start; i < a.length; ++i) {
            if (i > start && a[i] == a[i - 1]) {
                continue;
            }
            subset.add(a[i]);
            subsetHelper(a, i + 1, subset, subsets);
            subset.remove(subset.size() - 1);
        }
    }
}

解法2:BFS

public class Solution {
    class Struct {
        private List<Integer> subset;
        private int end;

        public Struct(List<Integer> subset, int end) {
            this.subset = subset;
            this.end = end;
        }
    }

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> subsets = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        Queue<Struct> queue = new ArrayDeque<Struct>();
        queue.offer(new Struct(new ArrayList<Integer>(), -1));
        while (!queue.isEmpty()) {
            List<Integer> subset = queue.peek().subset;
            int end = queue.poll().end;
            subsets.add(new ArrayList<Integer>(subset));
            for (int i = end + 1; i < nums.length; ++i) {
                if (i > end + 1 && nums[i] == nums[i - 1]) {
                    continue;
                }
                subset.add(nums[i]);
                queue.offer(new Struct(new ArrayList<Integer>(subset), i));
                subset.remove(subset.size() - 1);
            }
        }
        return subsets;
    }
}

相似题目:最小子集
lintcode-761
BFS

public class Solution {
    public int minElements(int[] arr) {
        int minCnt = arr.length;
        int sum = getArraySum(arr);
        Queue<List<Integer>> queue = new ArrayDeque<List<Integer>>();
        queue.offer(new ArrayList<Integer>());
        while (!queue.isEmpty()) {
            List<Integer> subset = queue.poll();
            if (2 * getListSum(subset) > sum) {
                minCnt = Math.min(minCnt, subset.size());
            }
            for (int i = 0; i < arr.length; ++i) {
                if (subset.size() > 0 && arr[i] <= subset.get(subset.size() - 1)) {
                    continue;
                }
                subset.add(arr[i]);
                queue.offer(new ArrayList<Integer>(subset));
                subset.remove(subset.size() - 1);
            }
        }
        return minCnt;
    }

    public int getArraySum(int[] a) {
        int sum = 0;
        for (int num : a) {
            sum += num;
        }
        return sum;
    }

    public int getListSum(List<Integer> list) {
        int sum = 0;
        for (int num : list) {
            sum += num;
        }
        return sum;
    }
}

数字组合

lintcode-135
组合型DFS+剪枝

public class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> combines = new ArrayList<List<Integer>>();
        Arrays.sort(candidates);
        combineHelper(candidates, target, 0, new ArrayList<Integer>(), combines);
        return combines;
    }

    public void combineHelper(int[] a, int target, int start, List<Integer> combine, List<List<Integer>> combines) {
        if (target == 0) {
            combines.add(new ArrayList<Integer>(combine));
            return;
        }
        if (target < 0) {
            return;
        }
        for (int i = start; i < a.length; ++i) {
            if (i > start && a[i] == a[i - 1]) {
                continue;
            }
            combine.add(a[i]);
            combineHelper(a, target - a[i], i, combine, combines);
            combine.remove(combine.size() - 1);
        }
    }
}

相似题目:数字组合II
lintcode-153
组合型DFS+剪枝

public class Solution {
    public List<List<Integer>> combinationSum2(int[] num, int target) {
        List<List<Integer>> combines = new ArrayList<List<Integer>>();
        Arrays.sort(num);
        combineHelper(num, target, 0, new ArrayList<Integer>(), combines);
        return combines;
    }

    public void combineHelper(int[] a, int target, int start, List<Integer> combine, List<List<Integer>> combines) {
        if (target == 0) {
            combines.add(new ArrayList<Integer>(combine));
            return;
        }
        if (target < 0) {
            return;
        }
        for (int i = start; i < a.length; ++i) {
            if (i > start && a[i] == a[i - 1]) {
                continue;
            }
            combine.add(a[i]);
            combineHelper(a, target - a[i], i + 1, combine, combines);
            combine.remove(combine.size() - 1);
        }
    }
}

全排列

lintcode-15
解法1:排列型DFS

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> permutes = new ArrayList<List<Integer>>();
        permuteHelper(nums, new boolean[nums.length], new ArrayList<Integer>(), permutes);
        return permutes;
    }

    public void permuteHelper(int[] a, boolean[] isVisited, List<Integer> permute, List<List<Integer>> permutes) {
        if (permute.size() == a.length) {
            permutes.add(new ArrayList<Integer>(permute));
            return;
        }
        for (int i = 0; i < a.length; ++i) {
            if (isVisited[i]) {
                continue;
            }
            permute.add(a[i]);
            isVisited[i] = true;
            permuteHelper(a, isVisited, permute, permutes);
            permute.remove(permute.size() - 1);
            isVisited[i] = false;
        }
    }
}

解法2:非递归

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> permutes = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        boolean hasNext = true;
        while (hasNext) {
            permutes.add(arrayToList(nums));
            hasNext = nextPermute(nums);
        }
        return permutes;
    }

    public boolean nextPermute(int[] a) {
        int index = a.length - 1;
        while (index > 0 && a[index] <= a[index - 1]) {
            index--;
        }
        if (index <= 0) {
            return false;
        }
        int minMore = a.length - 1;
        while (minMore > index && a[minMore] <= a[index - 1]) {
            minMore--;
        }
        swap(a, index - 1, minMore);
        reverse(a, index, a.length - 1);
        return true;
    }

    public void swap(int[] a, int p1, int p2) {
        int temp = a[p1];
        a[p1] = a[p2];
        a[p2] = temp;
    }

    public void reverse(int[] a, int start, int end) {
        while (start < end) {
            swap(a, start++, end--);
        }
    }

    public List<Integer> arrayToList(int[] a) {
        List<Integer> list = new ArrayList<Integer>();
        for (int num : a) {
            list.add(num);
        }
        return list;
    }
}

相似题目:带重复元素的排列
lintcode-16
解法1:排列型DFS+剪枝

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> permutes = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        permuteHelper(nums, new boolean[nums.length], new ArrayList<Integer>(), permutes);
        return permutes;
    }

    public void permuteHelper(int[] a, boolean[] isVisited, List<Integer> permute, List<List<Integer>> permutes) {
        if (permute.size() == a.length) {
            permutes.add(new ArrayList<Integer>(permute));
            return;
        }
        for (int i = 0; i < a.length; ++i) {
            if (isVisited[i] || i > 0 && a[i] == a[i - 1] && !isVisited[i - 1]) {
                continue;
            }
            permute.add(a[i]);
            isVisited[i] = true;
            permuteHelper(a, isVisited, permute, permutes);
            permute.remove(permute.size() - 1);
            isVisited[i] = false;
        }
    }
}

解法2:非递归

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> permutes = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        boolean hasNext = true;
        while (hasNext) {
            permutes.add(arrayToList(nums));
            hasNext = nextPermute(nums);
        }
        return permutes;
    }

    public boolean nextPermute(int[] a) {
        int index = a.length - 1;
        while (index > 0 && a[index] <= a[index - 1]) {
            index--;
        }
        if (index <= 0) {
            return false;
        }
        int minMore = a.length - 1;
        while (minMore > index && a[minMore] <= a[index - 1]) {
            minMore--;
        }
        swap(a, index - 1, minMore);
        reverse(a, index, a.length - 1);
        return true;
    }

    public void swap(int[] a, int p1, int p2) {
        int temp = a[p1];
        a[p1] = a[p2];
        a[p2] = temp;
    }

    public void reverse(int[] a, int start, int end) {
        while (start < end) {
            swap(a, start++, end--);
        }
    }

    public List<Integer> arrayToList(int[] a) {
        List<Integer> list = new ArrayList<Integer>();
        for (int num : a) {
            list.add(num);
        }
        return list;
    }
}

相似题目:下一个排列
lintcode-52
算法步骤

  1. 从右往左遍历数组 nums,直到找到一个位置 i,满足 nums[i]>nums[i-1] 或者 i==0
  2. i!=0 时,用 j 再次从右到左遍历 nums,寻找第一个 nums[j]>nums[i-1],交换 nums[j] 和 nums[i-1];注意,满足要求的 j 一定存在,且交换后 nums[i] 及右侧数组仍为降序数组
  3. 将 nums[i] 及右侧的数组翻转,使其升序
public class Solution {
    public int[] nextPermutation(int[] nums) {
        int rightPeak = nums.length - 1;
        while (rightPeak > 0 && nums[rightPeak] <= nums[rightPeak - 1]) {
            rightPeak--;
        }
        if (rightPeak > 0) {
            int minMore = nums.length - 1;
            while (minMore > rightPeak && nums[minMore] <= nums[rightPeak - 1]) {
                minMore--;
            }
            swap(nums, rightPeak - 1, minMore);
        }
        reverse(nums, rightPeak, nums.length - 1);
        return nums;
    }

    public void swap(int[] a, int p1, int p2) {
        int temp = a[p1];
        a[p1] = a[p2];
        a[p2] = temp;
    }

    public void reverse(int[] a, int start, int end) {
        while (start < end) {
            swap(a, start++, end--);
        }
    }
}

相似题目:上一个排列
lintcode-51

public class Solution {
    public List<Integer> previousPermuation(List<Integer> nums) {
        int index = nums.size() - 1;
        while (index > 0 && nums.get(index) >= nums.get(index - 1)) {
            index--;
        }
        if (index > 0) {
            int maxLess = nums.size() - 1;
            while (maxLess > index && nums.get(maxLess) >= nums.get(index - 1)) {
                maxLess--;
            }
            swap(nums, index - 1, maxLess);
        }
        reverse(nums, index, nums.size() - 1);
        return nums;
    }

    public void swap(List<Integer> list, int p1, int p2) {
        int temp = list.get(p1);
        list.set(p1, list.get(p2));
        list.set(p2, temp);
    }

    public void reverse(List<Integer> list, int start, int end) {
        while (start < end) {
            swap(list, start++, end--);
        }
    }
}

康托展开

cantor-expansion
康托展开:给出排列(按字典排序),求排列序号
X = a n ( n − 1 ) ! + a n − 1 ( n − 2 ) ! + ⋯ + a 2 ⋅ 1 ! + a 1 ⋅ 0 ! X=a_n(n-1)!+a_{n-1}(n-2)!+\cdots+a_2\cdot 1!+a_1\cdot 0! X=an(n1)!+an1(n2)!++a21!+a10!
康托函数是双射函数,逆康托展开:给出排列序号,求对应的排列
排列序号
lintcode-197

public class Solution {
    public long permutationIndex(int[] a) {
        long order = 1, factor = 1;
        for (int i = a.length - 1; i >= 0; --i) {
            int cntRightLess = countRightLess(a, i);
            order += cntRightLess * factor;
            factor *= a.length - i;
        }
        return order;
    }

    public int countRightLess(int[] a, int index) {
        int cnt = 0;
        for (int i = index + 1; i < a.length; ++i) {
            if (a[i] < a[index]) {
                cnt++;
            }
        }
        return cnt;
    }
}

排列序号
lintcode-198

public class Solution {
    public long permutationIndexII(int[] a) {
        long order = 1, factor = 1, repeat = 1;
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = a.length - 1; i >= 0; --i) {
            map.put(a[i], map.getOrDefault(a[i], 0) + 1);
            repeat *= map.get(a[i]);
            int count = countRightLess(a, i);
            order += count * factor / repeat;
            factor *= a.length - i;
        }
        return order;
    }

    public int countRightLess(int[] a, int index) {
        int cnt = 0;
        for (int i = index + 1; i < a.length; ++i) {
            if (a[i] < a[index]) {
                cnt++;
            }
        }
        return cnt;
    }
}

第k个排列
lintcode-388

public class Solution {
    public String getPermutation(int n, int k) {
        String permute = new String();
        List<Integer> list = constructList(n);
        int order = k - 1, factor = calculateFactor(n);
        for (int i = 1; i <= n; ++i) {
            int cnt = order / factor;
            permute += String.valueOf(list.get(cnt));
            list.remove(cnt);
            order %= factor;
            factor = i < n ? factor / (n - i) : 1;
        }
        return permute;
    }

    public List<Integer> constructList(int n) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 1; i <= n; ++i) {
            list.add(i);
        }
        return list;
    }

    public int calculateFactor(int n) {
        int product = 1;
        for (int i = 2; i < n; ++i) {
            product *= i;
        }
        return product;
    }
}

跳马问题

lintcode-611
解法1:BFS

public class Solution {
    public int shortestPath(boolean[][] grid, Point source, Point destination) {
        int[][] biases = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
        int path = 0;
        Queue<Point> queue = new ArrayDeque<Point>();
        queue.offer(new Point(source.x, source.y));
        grid[source.x][source.y] = true;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; ++i) {
                Point curr = queue.poll();
                if (curr.x == destination.x && curr.y == destination.y) {
                    return path;
                }
                for (int[] bias : biases) {
                    int nextX = curr.x + bias[0], nextY = curr.y + bias[1];
                    if (!isValid(grid, nextX, nextY)) {
                        continue;
                    }
                    queue.offer(new Point(nextX, nextY));
                    grid[nextX][nextY] = true;
                }
            }
            path++;
        }
        return -1;
    }

    public boolean isValid(boolean[][] a, int x, int y) {
        if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
            return false;
        }
        return !a[x][y];
    }
}

解法2:双向BFS
双向BFS适用条件:有起始点,无向图

public class Solution {
    public int shortestPath(boolean[][] grid, Point source, Point destination) {
        int[][] biases = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
        int path = 0;
        Queue<Point> forwQueue = new ArrayDeque<Point>(), backQueue = new ArrayDeque<Point>();
        forwQueue.offer(new Point(source.x, source.y));
        backQueue.offer(new Point(destination.x, destination.y));
        boolean[][] isVisitedForw = new boolean[grid.length][grid[0].length], isVisitedBack = new boolean[grid.length][grid[0].length];
        isVisitedForw[source.x][source.y] = true;
        isVisitedBack[destination.x][destination.y] = true;
        while (!forwQueue.isEmpty() && !backQueue.isEmpty()) {
            int forwSize = forwQueue.size(), backSize = backQueue.size();
            for (int i = 0; i < forwSize; ++i) {
                Point curr = forwQueue.poll();
                if (isVisitedBack[curr.x][curr.y]) {
                    return path;
                }
                for (int[] bias : biases) {
                    int nextX = curr.x + bias[0], nextY = curr.y + bias[1];
                    if (!isValid(grid, nextX, nextY) || isVisitedForw[nextX][nextY]) {
                        continue;
                    }
                    forwQueue.offer(new Point(nextX, nextY));
                    isVisitedForw[nextX][nextY] = true;
                }
            }
            path++;
            for (int i = 0; i < backSize; ++i) {
                Point curr = backQueue.poll();
                if (isVisitedForw[curr.x][curr.y]) {
                    return path;
                }
                for (int[] bias : biases) {
                    int nextX = curr.x + bias[0], nextY = curr.y + bias[1];
                    if (!isValid(grid, nextX, nextY) || isVisitedBack[nextX][nextY]) {
                        continue;
                    }
                    
                    backQueue.offer(new Point(nextX, nextY));
                    isVisitedBack[nextX][nextY] = true;
                }
            }
            path++;
        }
        return -1;
    }

    public boolean isValid(boolean[][] a, int x, int y) {
        if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
            return false;
        }
        return !a[x][y];
    }
}

相似问题:跳马问题II
lintcode-630
解法1:BFS

public class Solution {
    public int shortestPath2(boolean[][] grid) {
        int[][] biases = {{1, 2}, {-1, 2}, {2, 1}, {-2, 1}};
        int path = 0;
        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.offer(new int[]{0, 0});
        grid[0][0] = true;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; ++i) {
                int[] curr = queue.poll();
                if (curr[0] == grid.length - 1 && curr[1] == grid[0].length - 1) {
                    return path;
                }
                for (int[] bias : biases) {
                    int nextX = curr[0] + bias[0], nextY = curr[1] + bias[1];
                    if (!isValid(grid, nextX, nextY)) {
                        continue;
                    }
                    queue.offer(new int[]{nextX, nextY});
                    grid[nextX][nextY] = true;
                }
            }
            path++;
        }
        return -1;
    }

    public boolean isValid(boolean[][] a, int x, int y) {
        if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
            return false;
        }
        return !a[x][y];
    }
}

解法2:双向BFS


解法3:坐标型DP

public class Solution {
    public int shortestPath2(boolean[][] grid) {
        int[][] biases = {{1, 2}, {-1, 2}, {2, 1}, {-2, 1}};
        int[][] state = new int[grid.length][grid[0].length];
        for (int[] a : state) {
            Arrays.fill(a, -1);
        }
        state[0][0] = 0;
        for (int y = 0; y < grid[0].length; ++y) {
            for (int x = 0; x < grid.length; ++x) {
                if (grid[x][y]) {
                    continue;
                }
                int minPath = Integer.MAX_VALUE;
                for (int[] bias : biases) {
                    if (!isValid(grid, x - bias[0], y - bias[1])) {
                        continue;
                    }
                    if (state[x - bias[0]][y - bias[1]] > -1) {
                        minPath = Math.min(minPath, state[x - bias[0]][y - bias[1]]);
                    }
                }
                if (minPath < Integer.MAX_VALUE) {
                    state[x][y] = minPath + 1;
                }
            }
        }
        return state[grid.length - 1][grid[0].length - 1];
    }

    public boolean isValid(boolean[][] a, int x, int y) {
        if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
            return false;
        }
        return !a[x][y];
    }
}

迷宫

lintcode-787
解法1:BFS

public class Solution {
    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        int[][] biases = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.offer(start);
        boolean[][] isVisited = new boolean[maze.length][maze[0].length];
        while (!queue.isEmpty()) {
            int[] curr = queue.poll();
            isVisited[curr[0]][curr[1]] = true;
            if (curr[0] == destination[0] && curr[1] == destination[1]) {
                return true;
            }
            for (int[] bias : biases) {
                int[] next = getNext(maze, curr[0], curr[1], bias);
                if (!isValid(maze, next[0], next[1]) || isVisited[next[0]][next[1]]) {
                    continue;
                }
                queue.offer(next);
            }
        }
        return false;
    }

    public int[] getNext(int[][] a, int x, int y, int[] bias) {
        while (isValid(a, x, y)) {
            x += bias[0];
            y += bias[1];
        }
        return new int[]{x - bias[0], y - bias[1]};
    }

    public boolean isValid(int[][] a, int x, int y) {
        if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
            return false;
        }
        return a[x][y] == 0;
    }
}

解法2:双向BFS


相似问题:迷宫II
lintcode-788
解法1:BFS

public class Solution {
    public int shortestDistance(int[][] maze, int[] start, int[] destination) {
        int[][] biases = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.offer(start);
        int[][] path = new int[maze.length][maze[0].length];
        for (int[] a : path) {
            Arrays.fill(a, -1);
        }
        path[start[0]][start[1]] = 0;
        while (!queue.isEmpty()) {
            int[] curr = queue.poll();
            for (int[] bias : biases) {
                int[] next = getNextAndStep(maze, curr[0], curr[1], bias);
                if (curr[0] == next[0] && curr[1] == next[1]) {
                    continue;
                }
                int nextPath = path[curr[0]][curr[1]] + next[2];
                if (path[next[0]][next[1]] == -1 || nextPath < path[next[0]][next[1]]) {
                    path[next[0]][next[1]] = nextPath;
                    queue.offer(new int[]{next[0], next[1]});
                }
            }
        }
        return path[destination[0]][destination[1]];
    }

    public int[] getNextAndStep(int[][] a, int x, int y, int[] bias) {
        int cntStep = -1;
        while (isValid(a, x, y)) {
            x += bias[0];
            y += bias[1];
            cntStep++;
        }
        return new int[]{x - bias[0], y - bias[1], cntStep};
    }

    public boolean isValid(int[][] a, int x, int y) {
        if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
            return false;
        }
        return a[x][y] == 0;
    }
}

解法2:双向BFS


单词接龙

lintcode-120
解决BFS问题先构图(无向or有向):Map<Type>: Type -> Set<Type>
解法1:BFS

public class Solution {
    public int ladderLength(String start, String end, Set<String> dict) {
        int path = 1;
        dict.add(start);
        dict.add(end);
        Map<String, Set<String>> graph = constructGraph(dict);
        Queue<String> queue = new ArrayDeque<String>();
        queue.offer(start);
        dict.remove(start);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; ++i) {
                String curr = queue.poll();
                if (curr.equals(end)) {
                    return path;
                }
                for (String next : graph.get(curr)) {
                    if (!dict.contains(next)) {
                        continue;
                    }
                    queue.offer(next);
                    dict.remove(next);
                }
            }
            path++;
        }
        return -1;
    }

    public Map<String, Set<String>> constructGraph(Set<String> dict) {
        Map<String, Set<String>> graph = new HashMap<String, Set<String>>();
        for (String word : dict) {
            Set<String> nexts = getNextWords(word, dict);
            graph.put(word, nexts);
        }
        return graph;
    }

    public Set<String> getNextWords(String word, Set<String> dict) {
        Set<String> nexts = new HashSet<String>();
        char[] alphabet = ("abcdefghijklmnopqrstuvwxyz").toCharArray();
        for (int i = 0; i < word.length(); ++i) {
            String prefix = word.substring(0, i), suffix = word.substring(i + 1);
            for (int j = 0; j < 26; ++j) {
                if (word.charAt(i) == alphabet[j]) {
                    continue;
                }
                String next = prefix + alphabet[j] + suffix;
                if (dict.contains(next)) {
                    nexts.add(next);
                }
            }
        }
        return nexts;
    }
}

解法2:双向BFS

public class Solution {
    public int ladderLength(String start, String end, Set<String> dict) {
        int path = 1;
        dict.add(start);
        dict.add(end);
        Map<String, Set<String>> graph = constructGraph(dict);
        Queue<String> forwQueue = new ArrayDeque<String>(), backQueue = new ArrayDeque<String>();
        forwQueue.offer(start);
        backQueue.offer(end);
        Set<String> forwSet = new HashSet<String>(), backSet = new HashSet<String>();
        forwSet.add(start);
        backSet.add(end);
        while (!forwQueue.isEmpty() && !backQueue.isEmpty()) {
            int forwSize = forwQueue.size(), backSize = backQueue.size();
            for (int i = 0; i < forwSize; ++i) {
                String curr = forwQueue.poll();
                if (backSet.contains(curr)) {
                    return path;
                }
                for (String next : graph.get(curr)) {
                    if (forwSet.contains(next)) {
                        continue;
                    }
                    forwQueue.offer(next);
                    forwSet.add(next);
                }
            }
            path++;
            for (int i = 0; i < backSize; ++i) {
                String curr = backQueue.poll();
                if (forwSet.contains(curr)) {
                    return path;
                }
                for (String next : graph.get(curr)) {
                    if (backSet.contains(next)) {
                        continue;
                    }
                    backQueue.offer(next);
                    backSet.add(next);
                }
            }
            path++;
        }
        return -1;
    }

    public Map<String, Set<String>> constructGraph(Set<String> dict) {
        Map<String, Set<String>> graph = new HashMap<String, Set<String>>();
        for (String word : dict) {
            Set<String> nexts = getNextWords(word, dict);
            graph.put(word, nexts);
        }
        return graph;
    }

    public Set<String> getNextWords(String word, Set<String> dict) {
        Set<String> nexts = new HashSet<String>();
        char[] alphabet = ("abcdefghijklmnopqrstuvwxyz").toCharArray();
        for (int i = 0; i < word.length(); ++i) {
            String prefix = word.substring(0, i), suffix = word.substring(i + 1);
            for (int j = 0; j < 26; ++j) {
                if (word.charAt(i) == alphabet[j]) {
                    continue;
                }
                String next = prefix + alphabet[j] + suffix;
                if (dict.contains(next)) {
                    nexts.add(next);
                }
            }
        }
        return nexts;
    }
}

相似问题:单词接龙II
linrcode-121
BFS+DFS


数独

lintcode-802
解法1:DFS

public class Solution {
    public void solveSudoku(int[][] board) {
        boolean[][] row = new boolean[9][10], col = new boolean[9][10], box = new boolean[9][10];
        getIntialized(board, row, col, box);
        sudokuHelper(board, 0, row, col, box);
    }

    public boolean sudokuHelper(int[][] a, int index, boolean[][] row, boolean[][] col, boolean[][] box) {
        if (index == 81) {
            return true;
        }
        int x = index / 9, y = index % 9;
        if (a[x][y] > 0) {
            return sudokuHelper(a, index + 1, row, col, box);
        }
        for (int value = 1; value <= 9; ++value) {
            if (!isValid(x, y, value, row, col, box)) {
                continue;
            }
            a[x][y] = value;
            row[x][value] = true;
            col[y][value] = true;
            box[x / 3 * 3 + y / 3][value] = true;
            if (sudokuHelper(a, index + 1, row, col, box)) {
                return true;
            }
            a[x][y] = 0;
            row[x][value] = false;
            col[y][value] = false;
            box[x / 3 * 3 + y / 3][value] = false;
        }
        return false;
    }

    public void getIntialized(int[][] a, boolean[][] row, boolean[][] col, boolean[][] box) {
        for (int i = 0; i < 81; ++i) {
            int x = i / 9, y = i % 9, value = a[x][y];
            if (value == 0) {
                continue;
            }
            row[x][value] = true;
            col[y][value] = true;
            box[x / 3 * 3 + y / 3][value] = true;
        }
    }

    public boolean isValid(int x, int y, int value, boolean[][] row, boolean[][] col, boolean[][] box) {
        if (row[x][value] || col[y][value]) {
            return false;
        } // row, col
        if (box[x / 3 * 3 + y / 3][value]) {
            return false;
        } // 9x9 box
        return true;
    }
}
public class Solution {
    public void solveSudoku(int[][] board) {
        sudokuHelper(board, 0);
    }

    public boolean sudokuHelper(int[][] a, int index) {
        if (index == 81) {
            return true;
        }
        int x = index / 9, y = index % 9;
        if (a[x][y] > 0) {
            return sudokuHelper(a, index + 1);
        }
        for (int value = 1; value <= 9; ++value) {
            if (!isValid(a, x, y, value)) {
                continue;
            }
            a[x][y] = value;
            if (sudokuHelper(a, index + 1)) {
                return true;
            }
            a[x][y] = 0;
        }
        return false;
    }

    public boolean isValid(int[][] a, int x, int y, int value) {
        for (int i = 0; i < 9; ++i) {
            if (a[x][i] == value || a[i][y] == value) {
                return false;
            } // row, col
            if (a[x / 3 * 3 + i / 3][y / 3 * 3 + i % 3] == value) {
                return false;
            } // 9x9 box
        }
        return true;
    }
}

解法2:DFS+搜索顺序优化


旅行商问题

lintcode-816
解法1:DFS

public class Solution {
    class Result {
        private int minCost;

        public Result() {
            this.minCost = Integer.MAX_VALUE;
        }
    }

    public int minCost(int n, int[][] roads) {
        Result minCost = new Result();
        int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
        Set<Integer> visitedNodeSet = new HashSet<Integer>();
        visitedNodeSet.add(1);
        minCostHelper(n, 1, adjacentMatrix, 0, visitedNodeSet, minCost);
        return minCost.minCost;
    }

    public void minCostHelper(int n, int curNode, int[][] adjacentMatrix, int totalCost, Set<Integer> visitedNodeSet, Result minCost) {
        if (visitedNodeSet.size() == n) {
            minCost.minCost = Math.min(minCost.minCost, totalCost);
            return;
        }
        for (int nexNode = 1; nexNode <= n; ++nexNode) {
            if (visitedNodeSet.contains(nexNode)) {
                continue;
            }
            visitedNodeSet.add(nexNode);
            minCostHelper(n, nexNode, adjacentMatrix, totalCost + adjacentMatrix[curNode][nexNode], visitedNodeSet, minCost);
            visitedNodeSet.remove(nexNode);
        }
    }

    public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
        int[][] matrix = new int[numNode + 1][numNode + 1];
        for (int i = 0; i <= numNode; ++i) {
            for (int j = 0; j <= numNode; ++j) {
                matrix[i][j] = Integer.MAX_VALUE >> 4;
            }
        }
        for (int i = 0; i < edges.length; ++i) {
            int a = edges[i][0];
            int b = edges[i][1];
            int c = edges[i][2];
            matrix[a][b] = Math.min(matrix[a][b], c);
            matrix[b][a] = Math.min(matrix[b][a], c);
        } // initialization
        return matrix;
    }
}

解法2:DFS+最优化剪枝

public class Solution {
    class Result {
        private int minCost;

        public Result() {
            this.minCost = Integer.MAX_VALUE;
        }
    }

    public int minCost(int n, int[][] roads) {
        Result minCost = new Result();
        List<Integer> path = new ArrayList<Integer>();
        path.add(1);
        Set<Integer> visitedNodeSet = new HashSet<Integer>();
        visitedNodeSet.add(1);
        int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
        minCostHelper(n, 1, path, visitedNodeSet, adjacentMatrix, 0, minCost);
        return minCost.minCost;
    }

    public void minCostHelper(int n, int curNode, List<Integer> path, Set<Integer> visitedNodeSet, int[][] adjacentMatrix, int totalCost, Result minCost) {
        if (visitedNodeSet.size() == n) {
            minCost.minCost = Math.min(minCost.minCost, totalCost);
            return;
        }
        for (int nexNode = 1; nexNode <= n; ++nexNode) {
            if (visitedNodeSet.contains(nexNode) || hasBetterCase(nexNode, path, adjacentMatrix)) {
                continue;
            }
            path.add(nexNode);
            visitedNodeSet.add(nexNode);
            minCostHelper(n, nexNode, path, visitedNodeSet, adjacentMatrix, totalCost + adjacentMatrix[curNode][nexNode], minCost);
            visitedNodeSet.remove(nexNode);
            path.remove(path.size() - 1);
        }
    }

    public boolean hasBetterCase(int node, List<Integer> path, int[][] adjacentMatrix) {
        for (int i = 1; i < path.size(); ++i) {
            if (adjacentMatrix[path.get(i - 1)][path.get(i)] + adjacentMatrix[path.get(path.size() - 1)][node] > adjacentMatrix[path.get(i - 1)][path.get(path.size() - 1)] + adjacentMatrix[path.get(i)][node]) {
                return true;
            }
        }
        return false;
    }

    public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
        int[][] matrix = new int[numNode + 1][numNode + 1];
        for (int i = 0; i <= numNode; ++i) {
            for (int j = 0; j <= numNode; ++j) {
                matrix[i][j] = Integer.MAX_VALUE >> 4;
            }
        }
        for (int i = 0; i < edges.length; ++i) {
            int a = edges[i][0];
            int b = edges[i][1];
            int c = edges[i][2];
            matrix[a][b] = Math.min(matrix[a][b], c);
            matrix[b][a] = Math.min(matrix[b][a], c);
        } // initialization
        return matrix;
    }
}

解法3:状态压缩DP

public class Solution {
    public int minCost(int n, int[][] roads) {
        int minCost = Integer.MAX_VALUE;
        int sizeState = 1 << n;
        int[][] stateNode = getStateNode(sizeState, n);
        int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
        for (int curState = 0; curState < sizeState; ++curState) {
            for (int curNode = 2; curNode <= n; ++curNode) {
                if ((curState & 1 << (curNode - 1)) == 0) {
                    continue;
                }
                int preState = curState ^ 1 << (curNode - 1);
                for (int preNode = 1; preNode <= n; ++preNode) {
                    if ((preState & 1 << (preNode - 1)) == 0) {
                        continue;
                    }
                    stateNode[curState][curNode] = Math.min(stateNode[curState][curNode], stateNode[preState][preNode] + adjacentMatrix[preNode][curNode]);
                }
            }
        }
        for (int node = 1; node <= n; ++node) {
            minCost = Math.min(minCost, stateNode[sizeState - 1][node]);
        }
        return minCost;
    }

    public int[][] getStateNode(int sizeState, int numNode) {
        int[][] matrix = new int[sizeState][numNode + 1];
        for (int i = 0; i < sizeState; ++i) {
            for (int j = 0; j <= numNode; ++j) {
                matrix[i][j] = Integer.MAX_VALUE >> 4;
            }
        }
        matrix[1][1] = 0; // initialization
        return matrix;
    }

    public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
        int[][] matrix = new int[numNode + 1][numNode + 1];
        for (int i = 0; i <= numNode; ++i) {
            for (int j = 0; j <= numNode; ++j) {
                matrix[i][j] = Integer.MAX_VALUE >> 4;
            }
        }
        for (int i = 0; i < edges.length; ++i) {
            int a = edges[i][0];
            int b = edges[i][1];
            int c = edges[i][2];
            matrix[a][b] = Math.min(matrix[a][b], c);
            matrix[b][a] = Math.min(matrix[b][a], c);
        } // initialization
        return matrix;
    }
}

解法4:随机化算法

public class Solution {
    public int RANDOM_TIME = 1000;
    public Random rand = new Random(1000);

    public int minCost(int n, int[][] roads) {
        int minCost = Integer.MAX_VALUE;
        int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
        for (int time = 0; time < RANDOM_TIME; ++time) {
            List<Integer> path = getRandomPath(n);
            int cost = adjustToBetterCase(n, path, adjacentMatrix);
            minCost = Math.min(minCost, cost);
        }
        return minCost;
    }

    // all random permutation is with the same probability
    public List<Integer> getRandomPath(int numNode) {
        List<Integer> path = new ArrayList<Integer>();
        for (int i = 1; i <= numNode; ++i) {
            path.add(i);
        }
        for (int i = 2; i < numNode; ++i) {
            int j = rand.nextInt(1000) % i + 1; // [0, i) -> [1, i]
            swap(path, i, j);
        }
        return path;
    }

    public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
        int[][] matrix = new int[numNode + 1][numNode + 1];
        for (int i = 0; i <= numNode; ++i) {
            for (int j = 0; j <= numNode; ++j) {
                matrix[i][j] = Integer.MAX_VALUE >> 4;
            }
        }
        for (int i = 0; i < edges.length; ++i) {
            int a = edges[i][0];
            int b = edges[i][1];
            int c = edges[i][2];
            matrix[a][b] = Math.min(matrix[a][b], c);
            matrix[b][a] = Math.min(matrix[b][a], c);
        } // initialization
        return matrix;
    }

    public int adjustToBetterCase(int numNode, List<Integer> path, int[][] adjacentMatrix) {
        int cost = 0;
        boolean isAdjusted = true;
        while (isAdjusted) {
            isAdjusted = false;
            for (int i = 1; i < numNode; ++i) {
                for (int j = i + 1; j < numNode; ++j) {
                    // swap strategy
                    if (canSwap(i, j, path, adjacentMatrix)) {
                        swap(path, i, j);
                        isAdjusted = true;
                    }
                    // // reverse strategy
                    // if (canReverse(i, j, path, adjacentMatrix)) {
                    //     reverse(path, i, j);
                    //     isAdjusted = true;
                    // }
                }
            }
        }
        for (int node = 1; node < numNode; ++node) {
            cost += adjacentMatrix[path.get(node - 1)][path.get(node)];
        }
        return cost;
    }

    public boolean canSwap(int i, int j, List<Integer> path, int[][] adjacentMatrix) {
        int before = adjacentMatrix[path.get(i - 1)][path.get(i)] + adjacentMatrix[path.get(i)][path.get(i + 1)] + adjacentMatrix[path.get(j - 1)][path.get(j)];
        int after = adjacentMatrix[path.get(i - 1)][path.get(j)] + adjacentMatrix[path.get(j)][path.get(i + 1)] + adjacentMatrix[path.get(j - 1)][path.get(i)];
        if (j + 1 < path.size()) {
            before += adjacentMatrix[path.get(j)][path.get(j + 1)];
            after += adjacentMatrix[path.get(i)][path.get(j + 1)];
        }
        return before > after;
    }

    // reverse strategy can be used only when: adjacentMatrix[i][j] == adjacentMatrix[j][i]
    public boolean canReverse(int i, int j, List<Integer> path, int[][] adjacentMatrix) {
        int before = adjacentMatrix[path.get(i - 1)][path.get(i)];
        int after = adjacentMatrix[path.get(i - 1)][path.get(j)];
        if (j + 1 < path.size()) {
            before += adjacentMatrix[path.get(j)][path.get(j + 1)];
            after += adjacentMatrix[path.get(i)][path.get(j + 1)];
        }
        return before > after;
    }

    public void swap(List<Integer> a, int p1, int p2) {
        int temp = a.get(p1);
        a.set(p1, a.get(p2));
        a.set(p2, temp);
    }

    public void reverse(List<Integer> a, int start, int end) {
        while (start < end) {
            swap(a, start++, end--);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值