分治和回溯相关题目
文章目录
- 分治和回溯相关题目
- 一、[50. Pow(x, n)](https://leetcode-cn.com/problems/powx-n/), 高频
- 二、[78. 子集](https://leetcode-cn.com/problems/subsets/)
- 三、[169. 多数元素](https://leetcode-cn.com/problems/majority-element/)
- 四、[17. 电话号码的字母组合](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/)
- 五、[51. N 皇后](https://leetcode-cn.com/problems/n-queens/)
- 六、12. 指令计算器设计
一、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()));
}