10、字符串的不同排列
题目
给出一个字符串,找到它的所有排列,注意同一个字符串不要打印两次。
样例
给出 “abb”,返回 [“abb”, “bab”, “bba”]。
给出 “aabb”,返回 [“aabb”, “abab”, “baba”, “bbaa”, “abba”, “baab”]。代码
public class Solution {
public List<String> stringPermutation2(String str) {
List<String> results = new ArrayList<>();
if (str == null) {
return results;
}
ArrayList<Character> list = new ArrayList<>();
char[] s = str.toCharArray();
Arrays.sort(s);
boolean[] flag = new boolean[s.length];
dfsHelper(s, flag, list, results);
return results;
}
private void dfsHelper(char[] s,
boolean[] flag,
ArrayList<Character> list,
List<String> results) {
if (list.size() == s.length) {
results.add(toStr(list));
}
for (int i = 0; i < s.length; i++) {
if (flag[i]) {
continue;
}
if (i != 0 && s[i] == s[i - 1] && !flag[i - 1]) {
continue;
}
list.add(s[i]);
flag[i] = true;
dfsHelper(s, flag, list, results);
flag[i] = false;
list.remove(list.size() - 1);
}
}
private String toStr(ArrayList<Character> list) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
}
return sb.toString();
}
}
135、数字组合
题目
给出一组候选数字(C)和目标数字(T),找到C中所有的组合,使找出的数字和为T。C中的数字可以无限制重复被选取。
例如,给出候选数组[2,3,6,7]和目标数字7,所求的解为:
[7],
[2,2,3]
注意事项
所有的数字(包括目标数字)均为正整数。
元素组合(a1, a2, … , ak)必须是非降序(ie, a1 ≤ a2 ≤ … ≤ ak)。
解集不能包含重复的组合。
样例
给出候选数组[2,3,6,7]和目标数字7
返回 [[7],[2,2,3]]代码
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (candidates == null || candidates.length == 0) {
return result;
}
Arrays.sort(candidates);
List<Integer> list = new ArrayList<>();
dfsHelper(candidates, 0, 0, target, list, result);
return result;
}
private void dfsHelper(int[] candidates,
int pos,
int sum,
int target,
List<Integer> list,
List<List<Integer>> result) {
if (sum == target) {
result.add(new ArrayList<Integer>(list));
}
for (int i = pos; i < candidates.length; i++) {
if (i != pos && candidates[i] == candidates[i - 1]) {
continue;
}
if (candidates[i] + sum > target) {
break;
}
list.add(candidates[i]);
dfsHelper(candidates, i, candidates[i] + sum, target, list, result);
list.remove(list.size() - 1);
}
}
}
153、数字组合 II
题目
给出一组候选数字(C)和目标数字(T),找出C中所有的组合,使组合中数字的和为T。C中每个数字在每个组合中只能使用一次。
注意事项
所有的数字(包括目标数字)均为正整数。
元素组合(a1, a2, … , ak)必须是非降序(ie, a1 ≤ a2 ≤ … ≤ ak)。
解集不能包含重复的组合。
样例
给出一个例子,候选数字集合为[10,1,6,7,2,1,5] 和目标数字 8 ,
解集为:[[1,7],[1,2,5],[2,6],[1,1,6]]代码
public class Solution {
public List<List<Integer>> combinationSum2(int[] num, int target) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (num == null || num.length == 0) {
return result;
}
List<Integer> list = new ArrayList<>();
Arrays.sort(num);
dfsHelper(num, 0, 0, target, list, result);
return result;
}
private void dfsHelper(int[] num,
int pos,
int sum,
int target,
List<Integer> list,
List<List<Integer>> result) {
if (sum == target) {
result.add(new ArrayList<Integer>(list));
}
for (int i = pos; i < num.length; i++) {
if (i != pos && num[i] == num[i - 1]) {
continue;
}
if (num[i] + sum > target) {
break;
}
list.add(num[i]);
dfsHelper(num, i + 1, num[i] + sum, target, list, result);
list.remove(list.size() - 1);
}
}
}
136、分割回文串
题目
给定一个字符串s,将s分割成一些子串,使每个子串都是回文串。
返回s所有可能的回文串分割方案。
样例
给出 s = “aab”,返回
[
[“aa”, “b”],
[“a”, “a”, “b”]
]代码
public class Solution {
public List<List<String>> partition(String s) {
List<List<String>> results = new ArrayList<List<String>>();
if (s == null || s.length() == 0) {
return results;
}
List<String> list = new ArrayList<String>();
dfsHelper(s, list, results);
return results;
}
private void dfsHelper(String s,
List<String> list,
List<List<String>> results) {
if (s.length() == 0) {
results.add(new ArrayList<String>(list));
}
for (int i = 0; i < s.length(); i++) {
if (!isPalind(s, i)) {
continue;
}
list.add(s.substring(0, i + 1));
dfsHelper(s.substring(i + 1), list, results);
list.remove(list.size() - 1);
}
}
private boolean isPalind(String s, int i) {
int start = 0;
int end = i;
while (start < end) {
if (s.charAt(start++) != s.charAt(end--)) {
return false;
}
}
return true;
}
}
108、分割回文串 II
-
题目
给定一个字符串s,将s分割成一些子串,使每个子串都是回文。
返回s符合要求的的最少分割次数。
【需要再来遍】 样例
比如,给出字符串s = “aab”,
返回 1, 因为进行一次分割可以将字符串s分割成[“aa”,”b”]这样两个回文子串代码
public class Solution {
public int minCut(String s) {
if (s == null || s.length() == 0) {
return 0;
}
boolean[][] isPalind = isPalindrome(s);
int[] f = new int[s.length() + 1];
f[0] = 0;
for (int i = 1; i <= s.length(); i++) {
f[i] = i;
for (int j = 0; j < i; j++) {
if (isPalind[j][i - 1]) {
f[i] = Math.min(f[i], f[j] + 1);
}
}
}
return f[s.length()] - 1;
}
private boolean[][] isPalindrome(String s) {
int len = s.length();
boolean[][] isPalind = new boolean[len][len];
for (int i = 0; i < len; i++) {
isPalind[i][i] = true;
}
for (int i = 0; i < len - 1; i++) {
isPalind[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
}
for (int length = 2; length < len; length++) {
for (int start = 0; start + length < len; start++) {
isPalind[start][start + length] = isPalind[start + 1][start + length - 1] && (s.charAt(start) == s.charAt(start + length));
}
}
return isPalind;
}
}
211、字符串置换
题目
给定两个字符串,请设计一个方法来判定其中一个字符串是否为另一个字符串的置换。
置换的意思是,通过改变顺序可以使得两个字符串相等。
样例
“abc” 为 “cba” 的置换。
“aabc” 不是 “abcc” 的置换。代码
public class Solution {
public boolean stringPermutation(String A, String B) {
if (A.length() != B.length()) {
return false;
}
int[] flag = new int[1000];
int len = A.length();
for (int i = 0; i < len; i++) {
flag[A.charAt(i)]++;
}
for (int i = 0; i < len; i++) {
flag[B.charAt(i)]--;
}
for (int i = 0; i < len; i++) {
if (flag[A.charAt(i)] != 0) {
return false;
}
}
return true;
}
}
51、上一个排列
题目
给定一个整数数组来表示排列,找出其上一个排列。
注意事项
排列中可能包含重复的整数
样例
给出排列[1,3,2,3],其上一个排列是[1,2,3,3]
给出排列[1,2,3,4],其上一个排列是[4,3,2,1]代码
public class Solution {
public ArrayList<Integer> previousPermuation(ArrayList<Integer> nums) {
int n = nums.size();
int i = n - 1;
while (i != 0 && nums.get(i) >= nums.get(i - 1)) {
i--;
}
if (i == 0) {
reverse(nums, 0, n - 1);
return nums;
}
reverse(nums, i, n - 1);
int j = i;
for (; j < n - 1; j++) {
if (nums.get(j) < nums.get(i - 1)) {
break;
}
}
swap(nums, i - 1, j);
return nums;
}
private void swap(ArrayList<Integer> nums, int i, int j) {
int temp = nums.get(i);
nums.set(i, nums.get(j));
nums.set(j, temp);
}
private void reverse(ArrayList<Integer> nums, int start, int end) {
for (; start < end; start++, end--) {
swap(nums, start, end);
}
}
}
52、下一个排列
题目
给定一个整数数组来表示排列,找出其之后的一个排列。
注意事项
排列中可能包含重复的整数
样例
给出排列[1,3,2,3],其下一个排列是[1,3,3,2]
给出排列[4,3,2,1],其下一个排列是[1,2,3,4]代码
public class Solution {
public int[] nextPermutation(int[] nums) {
if (nums == null) {
return nums;
}
int n = nums.length;
int i = n - 1;
while (i != 0 && nums[i] <= nums[i - 1]) {
i--;
}
if (i == 0) {
reverse(nums, i, n - 1);
return nums;
}
int j = n - 1;
for (; j > i - 1; j--) {
if (nums[j] > nums[i - 1]) {
break;
}
}
swap(nums, i - 1 , j);
reverse(nums, i, n - 1);
return nums;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private void reverse(int[] nums, int start, int end) {
for (; start < end; start++, end--) {
swap(nums, start, end);
}
}
}
190、下一个排列
题目
给定一个若干整数的排列,给出按正数大小进行字典序从小到大排序后的下一个排列。
如果没有下一个排列,则输出字典序最小的序列。
样例
左边是原始排列,右边是对应的下一个排列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1代码
public class Solution {
public void nextPermutation(int[] nums) {
if (nums == null) {
return;
}
int n = nums.length;
int i = n - 1;
while (i != 0 && nums[i] <= nums[i - 1]) {
i--;
}
if (i == 0) {
reverse(nums, 0, n - 1);
return;
}
int j = n - 1;
for (; j > i - 1; j--) {
if (nums[j] > nums[i - 1]) {
break;
}
}
swap(nums, i - 1, j);
reverse(nums, i, n - 1);
return;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private void reverse(int[] nums, int start, int end) {
for(; start < end; start++, end--) {
swap(nums, start, end);
}
}
}
197、排列序号
题目
给出一个不含重复数字的排列,求这些数字的所有排列按字典序排序后该排列的编号。其中,编号从1开始。
样例
例如,排列 [1,2,4] 是第 1 个排列。代码
public class Solution {
public long permutationIndex(int[] A) {
int[] flag = new int[A.length];
for (int i = 0; i < A.length; i++) {
for (int j = i + 1; j < A.length; j++) {
if (A[i] > A[j]) {
flag[i]++;
}
}
}
long result = 0;
for (int i = 0; i < A.length; i++) {
result += flag[i] * Jec(A.length - i - 1);
}
return result + 1;
}
private long Jec(int x) {
long ans = 1;
while (x > 0) {
ans *= (long) x;
x--;
}
return ans;
}
}
198、排列序号II
题目
给出一个可能包含重复数字的排列,求这些数字的所有排列按字典序排序后该排列在其中的编号。编号从1开始。
【需要再来一遍~】
样例
给出排列[1, 4, 2, 2],其编号为3。代码
public class Solution {
public long permutationIndexII(int[] A) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < A.length; i++) {
if (map.containsKey(A[i])) {
map.put(A[i], map.get(A[i]) + 1);
} else {
map.put(A[i], 1);
}
}
long result = 0;
for (int i = 0; i < A.length; i++) {
Map<Integer, Integer> flag = new HashMap<>();
for (int j = i + 1; j < A.length; j++) {
if (A[i] > A[j] && !flag.containsKey(A[j])) {
flag.put(A[j], 1);
map.put(A[j], map.get(A[j]) - 1);
result += getNum(map);
map.put(A[j], map.get(A[j]) + 1);
}
}
map.put(A[i], map.get(A[i]) - 1);
}
return result + 1;
}
private long getNum(Map<Integer, Integer> map) {
int sum = 0;
long dup = 1;
for (Integer v : map.values()) {
if (v == 0) {
continue;
}
sum += v;
dup *= Jec(v);
}
if (sum == 0) {
return sum;
}
return Jec(sum) / dup;
}
private long Jec(int x) {
long ans = 1;
while (x > 0) {
ans *= (long) x;
x--;
}
return ans;
}
}
107、单词切分
题目
给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词。
【需要再来一遍~】
样例
给出
s = “lintcode”
dict = [“lint”,”code”]
返回 true 因为”lintcode”可以被空格切分成”lint code”代码
public class Solution {
public boolean wordBreak(String s, Set<String> dict) {
if (s == null || s.length() == 0) {
return true;
} //?
if (dict.isEmpty()) {
return false;
}
int n = s.length();
boolean[] flag = new boolean[n + 1];
flag[n] = true;
int maxLen = getMax(dict);
for (int i = n - 1; i >= 0; i--) {
for (int j = i + 1; j - i <= maxLen && j <= n; j++) {
if (!flag[j]) {
continue;
}
String sub = s.substring(i, j);
if (dict.contains(sub)) {
flag[i] = true;
}
}
}
return flag[0];
}
private int getMax(Set<String> dict) {
int maxLen = Integer.MIN_VALUE;
for (String d : dict) {
maxLen = Math.max(maxLen, d.length());
}
return maxLen;
}
}
没有maxLen的话会超时~