leetcode
1、组合
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
package leetcode;
import java.util.ArrayList;
import java.util.List;
public class combine_77 {
public static void main(String[] args) {
int n = 4;
int k = 2;
List<List<Integer>> res = combine(n, k);
System.out.println(res);
}
static List<List<Integer>> list2 = new ArrayList<>();
static List<Integer> list = new ArrayList<>();
public static List<List<Integer>> combine(int n, int k) {
if (n <= 0 || k <= 0 || n < k) {
return list2;
}
combine1(n,k,1);
return list2;
}
public static void combine1(int n,int k,int index) {
if (k == list.size()) {
list2.add(new ArrayList<>(list));
return;
}
//k - pre.size() 是剩下还要寻找的数的个数。
for(int i=index;i<=n-(k-list.size())+1;i++) {
list.add(i);
combine1(n,k,i+1);
list.remove(list.size()-1);
}
}
}
2、子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
package leetcode;
import java.util.ArrayList;
import java.util.List;
public class subsets_78 {
public static void main(String[] args) {
int[] nums = { 1, 2, 3 };
List<List<Integer>> res =subsets(nums);
System.out.println(res);
}
static List<List<Integer>> list2 = new ArrayList<>();
static List<Integer> list = new ArrayList<>();
public static List<List<Integer>> subsets(int[] nums) {
list2.add(new ArrayList<>(list));
//如果数组包含重复元素加上这句
//Arrays.sort(nums);
combine(nums, 0, nums.length);
return list2;
}
public static void combine(int[] nums,int start,int end) {
for(int i=start;i<end;i++) {
//如果数组包含重复元素加上这句
// if(i>start&&nums[i]==nums[i-1]){
// continue;
// }
list.add(nums[i]);
list2.add(new ArrayList<>(list));
combine(nums,i+1,end);
list.remove(list.size()-1);
}
}
}
3、单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
package leetcode;
public class wordSearch_80 {
public static void main(String[] args) {
char[][] board = { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'E', 'S' }, { 'A', 'D', 'E', 'E' } };
String word = "ABCESEEEFS";
System.out.println(exist(board, word));
}
public static boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
int x = 0;
char[][] boardCopy = new char[m + 2][n + 2];
for (int i = 0; i < board[0].length; i++) {
boardCopy[0][i] = ' ';
boardCopy[boardCopy.length - 1][i] = ' ';
}
for (int i = 0; i < boardCopy.length; i++) {
boardCopy[i][0] = ' ';
boardCopy[i][boardCopy[0].length - 1] = ' ';
}
for (int i = 1; i < boardCopy.length - 1; i++) {
for (int j = 1; j < boardCopy[0].length - 1; j++) {
boardCopy[i][j] = board[i - 1][j - 1];
}
}
for (int i = 1; i < boardCopy.length; i++) {
for (int j = 1; j < boardCopy[0].length; j++) {
if (word.charAt(x) == boardCopy[i][j]) {
boolean[][] used = new boolean[m+2][n+2];
boolean res = find(boardCopy, word, i, j, x,used);
if(res) {
return res;
}
}
}
}
return false;
}
public static boolean find(char[][] boardCopy, String word, int i, int j, int x,boolean[][] used) {
if (x == word.length()) {
return true;
} else {
if (used[i][j]==false&&word.charAt(x++) == boardCopy[i][j]) {
used[i][j]=true;
if (find(boardCopy, word, i + 1, j, x,used)) {//下
return true;
} else if (find(boardCopy, word, i, j + 1, x,used)) {//右
return true;
} else if (find(boardCopy, word, i - 1, j, x,used)) {//上
return true;
} else if (find(boardCopy, word, i, j - 1, x,used)) {//左
return true;
} else {
used[i][j]=false;
return false;
}
} else {
return false;
}
}
}
}
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5
, 并且原数组的前五个元素被修改为 1, 1, 2, 2,
3 。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7
, 并且原数组的前五个元素被修改为 0
, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。
方法:覆盖多余的重复项
算法:
我们使用了两个指针,i 是遍历指针,指向当前遍历的元素;j 指向下一个要覆盖元素的位置。
同样,我们用 count 记录当前数字出现的次数。count 的最小计数始终为 1。
我们从索引 1 开始一次处理一个数组元素。
若当前元素与前一个元素相同,即 nums[i]==nums[i-1],则 count++。若 count > 2,则说明遇到了多余的重复项。在这种情况下,我们只向前移动 i,而 j 不动。
若 count <=2,则我们将 i 所指向的元素移动到 j 位置,并同时增加 i 和 j。
若当前元素与前一个元素不相同,即 nums[i] != nums[i - 1],说明遇到了新元素,则我们更新 count = 1,并且将该元素移动到 j 位置,并同时增加 i 和 j。
当数组遍历完成,则返回 j。
package leetcode;
//删除排序数组中的重复项(leetcode 80)
public class removeDuplicates_80 {
public static void main(String[] args) {
int[] arr= {1,2,2,2,2,3,3,3,3};
System.out.println(removeDuplicates(arr));
for(int i:arr) {
System.out.print(i+" ");
}
}
public static int removeDuplicates(int[] nums) {
int j=1;int count=1;
for(int i=1;i<nums.length;i++) {
if(nums[i]==nums[i-1]) {
count++;
}else {
count=1;
}
if(count<=2) {
nums[j++]=nums[i];
}
}
return j;
}
}
5. 搜索旋转排序数组 II
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,0,1,2,2,5,6]
可能变为 [2,5,6,0,0,1,2]
)。
编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true
,否则返回 false
。
示例 1:
输入: nums = [2,5,6,0,0,1,2]
, target = 0
输出: true
示例 2:
输入: nums = [2,5,6,0,0,1,2]
, target = 3
输出: false
解题思路:
本题是需要使用二分查找,怎么分是关键,举个例子:
第一类
101111011110111 和 111011110111101 这种。此种情况下 nums[start] == nums[mid],分不清到底是前面有序还是后面有序,此时 start++ 即可。相当于去掉一个重复的干扰项。
第二类
222 333 444 555 666 777 111 这种,也就是 nums[start] < nums[mid]。此例子中就是 2 < 5;
这种情况下,前半部分有序。因此如果 nums[start] <=target<nums[mid],则在前半部分找,否则去后半部分找。
第三类
666 777 111 222 333 444 555 这种,也就是 nums[start] > nums[mid]。此例子中就是 6 > 2;
这种情况下,后半部分有序。因此如果 nums[mid] <target<=nums[end]。则在后半部分找,否则去前半部分找。
class Solution {
public boolean search(int[] nums, int target) {
if(nums.length==0)return false;
int start=0;
int end=nums.length-1;
int mid;
while(start<=end){
mid=start+(end-start)/2;
if(nums[mid]==target){
return true;
}
if(nums[start]==nums[mid]){
start++;
continue;
}
if(nums[start]<nums[mid]){
if(nums[start]<=target&&nums[mid]>target){
end=mid-1;
}else{
start=mid+1;
}
}
else if(nums[start]>nums[mid]){
if(nums[mid]<target&&nums[end]>=target){
start=mid+1;
}else{
end=mid-1;
}
}
}
return false;
}
}