算法:分治和回溯相关题目

分治和回溯相关题目

一、50. Pow(x, n), 高频

解法一:暴力法:超出时间限制

    public double myPow(double x, int n) {
        boolean flag = true;
        if (n<0) {
            flag = false;
            n = -n;
        }
        double res = 1.0;
        for (int i=1; i<=n; i++) {
            res *= x;
        }
        if (!flag) res = 1/res;
        return res;
    }

解法二:分治

    public double myPow(double x, int n) {
        return n>=0?solve(x, n):solve(1/x, -n);
    }

    private double solve(double x, int n) {
        if (n==0) return 1d;
        double y = solve(x, n/2);
        return n%2==0?y * y : y * y * x;
    }

二、78. 子集

解法一:递归

    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        int n = nums.length;
        for (int k=0; k<=n; k++) {
            solve(k, 0, 0, new Integer[k], nums, res);
        }
        return res;
    }

    private void solve(int k, int l, int i, Integer[] a, int[] nums, List<List<Integer>> res){
        if (l>=k) {
            res.add(Arrays.asList(a.clone()));
            return;
        }
        for (int j=i; j<=nums.length-k+l; j++) {
            a[l] = nums[j];
            solve(k, l+1, j+1, a, nums, res);
        }
    }

解法二:遍历

		def subsets(self, nums: List[int]) -> List[List[int]]:
        res=[[]]
        for v in nums:
            res += [item+[v] for item in res]
        return res;

解法三:递归,类比括号生成

    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> resultList = new ArrayList<>();
        solve(0, nums.length, nums, resultList, new ArrayList<>());
        return resultList;
    }

    private void solve(int level, int n, int[] nums, List<List<Integer>> resultList, List<Integer> list){
        if (level>=n) {
            resultList.add(new ArrayList<>(list));
            return;
        }
        solve(level+1, n, nums, resultList, list);
        list.add(nums[level]);
        solve(level+1, n, nums, resultList, list);
        list.remove(list.size()-1);
    }

三、169. 多数元素

3.1 解法一:递归

    public int majorityElement(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i=0; i<nums.length; i++) {
            map.put(nums[i], map.getOrDefault(nums[i], 0)+1);
            if (map.get(nums[i])>nums.length/2) {
                return nums[i];
            }
        }
        return -1;
    }

3.2 解法二:排序:Arrays.sort

    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }s

3.3 解法三:自定义堆排序

    public int majorityElement(int[] nums) {
        int N = nums.length;
        for (int k=N/2; k>=1; k--) {
            sink(k, N, nums);
        }
        while (N>1) {
            exch(nums, 1, N--);
            sink(1, N, nums);
        }
        return nums[nums.length/2];
    }

    private void sink(int k, int N, int[] nums){
        while (2*k<=N) {
            int j = 2 * k;
            if (j<N && less(nums, j, j+1)) j++;
            if (less(nums, j, k)) break;
            exch(nums, j, k);
            k = j;
        }
    }

    private boolean less(int[] nums, int i, int j) {
        return nums[i-1]<nums[j-1];
    }

    private void exch(int[] nums, int i, int j) {
        int t = nums[i-1];
        nums[i-1] = nums[j-1];
        nums[j-1] = t;
    }

3.4 解法四:分治 (最优)

    public int majorityElement(int[] nums) {
        return majorityElement(nums, 0, nums.length-1);
    }

    private int majorityElement(int[] nums, int low, int high) {
        if (low==high) return nums[low];
        int mid = (high-low)/2 + low;
        int left = majorityElement(nums, low, mid);
        int right = majorityElement(nums, mid+1, high);
        if (left == right) return left;
        int leftCount = numCount(left, low, mid, nums);
        int rightCount = numCount(right, mid+1, high, nums);
        return leftCount>rightCount?left:right;
    }

    private int numCount(int num, int i, int j, int[] nums) {
        int n = 0;
        for (int k=i; k<=j; k++) {
            if (nums[k]==num) n++;
        }
        return n;
    }

四、17. 电话号码的字母组合

要看完所有的情况,比如, 7和9 都是 4个按键。

4.1 递归

    public List<String> letterCombinations(String digits) {
        List<String> result = new ArrayList<>();
        solve(0, digits.length(), digits, new StringBuilder(), result);
        return result;
    }

    private void solve(int level, int n, String digits, StringBuilder sb, List<String> result) {
        if (level>=n) {
            if (n==0) return;
            result.add(sb.toString());
            return;
        }
        int v = Integer.parseInt(digits.charAt(level)+"");
        int num = 3;
        if (v==9 || v==7) num=4;
        char begin=(char)('a' + (v-2) * 3);
        if (v>7) begin ++;
        char end = (char)(begin + num-1);
        for (char b=begin; b<=end; b++) {
            sb.append(b);
            solve(level+1, n, digits, sb, result);
            sb.deleteCharAt(sb.length()-1);
        }
    } 

五、51. N 皇后

解法一:递归:通过列、撇、捺三个Set进行过滤

    private Set<Integer> cols = new HashSet<>();
    private Set<Integer> pies = new HashSet<>();
    private Set<Integer> nas = new HashSet<>();

    public List<List<String>> solveNQueens(int n) {
        List<Integer[]> res = new ArrayList<>();
        queensLie(n, 0, new Integer[n], res);
        List<List<String>> resList = changeResult(res);
        return resList;
    }

    private List<List<String>> changeResult(List<Integer[]> res) {
        List<List<String>> resList = new ArrayList<>(res.size());
        for (Integer[] a: res) {
            List<String> item = new ArrayList<>();
            for (Integer i: a) {
                char[] ca = new char[a.length];
                Arrays.fill(ca, '.');
                ca[i] = 'Q';
                item.add(String.valueOf(ca));
            }
            resList.add(item);
        }
        return resList;
    }

    private void queensLie(int n, int row, Integer[] lies, List<Integer[]> res) {
        if (row>=n) {
            res.add(lies.clone());
            return;
        }
        for (int lie=0; lie<n; lie++) {
            if (cols.contains(lie) || pies.contains(row-lie) || nas.contains(row+lie)) continue;
            cols.add(lie);
            pies.add(row-lie);
            nas.add(row+lie);
            lies[row]=lie;
            queensLie(n, row+1, lies, res);
            cols.remove(lie);
            pies.remove(row-lie);
            nas.remove(row+lie);
        }
    }

解法二:python的精简解法

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        def solve(cols: List[int], pies: List[int], nas: List[int]):
            if len(cols)==n:
                res.append(cols)
            for col in range(n):
                if col not in cols and len(cols)-col not in pies and len(cols)+col not in nas:
                    solve(cols+[col], pies+[len(cols)-col], nas+[len(cols)+col])
        res=[]
        solve([], [], [])
        return [[ '.'*v+'Q'+(n-v-1)*'.' for v in a] for a in res]

六、12. 指令计算器设计

我们知道高级编程语言中,有一种表达式叫三元表达式。比如 Java 语言中, 输入一个类似于 condition? 1:2。

如果 condition 为 true,那么返回 1,否则返回 2。

现在考虑设计一个类似的指令计算器,输入值为表达式,给定的表达式始终都是有效的并且只包含单个数字 0-9, ?, :, Y 和 N (Y 和 N 分别表示真和假)。

表达式支持复杂输入,解析顺序从右到左. 比如 "Y?1:N?2:3" 这种复杂表达式。那么请你设计一个算法支持计算类似指令,输出对应结果。

示例 1
输入: “Y?0:9”
输出: “0”
解释: 如果条件为真,结果为 0;否则,结果为 9。

示例 2
输入: “Y?1:N?2:3”
输出: “1”

6.1 解法一:使用队列

    public String computeTernary(String expression) {
      if (expression==null || expression.length()==0) return "";
      Deque<Character> deque = new LinkedList<>();
      char c = expression.charAt(expression.length()-1);
      for (int i=expression.length()-1; i>=0; i--) {
        char v = expression.charAt(i);
        if (v>='0' && v<='9') deque.addFirst(v);
        if (v=='Y' || v=='N') {
          char c1 = deque.pop();
          char c2 = deque.pop();
          c=v=='Y'?c1:c2;
          deque.addFirst(c);
        }
      }
      return String.valueOf(c);
    }

6.2 解法二:使用递归

    public String computeTernary(String expression) {
      if (expression==null || expression.length()==0) return "";
      char c = expression.charAt(0);
      if (c>='0' && c<='9') return String.valueOf(c);
      return expression.charAt(0)=='Y'?String.valueOf(expression.charAt(2)):computeTernary(expression.substring(4, expression.length()));
    }
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值