LeetCode31 下一个排列
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
class Solution {
public void nextPermutation(int[] nums) {
if(nums == null || nums.length <= 1){
return;
}
int t = nums.length - 1,p = t,temp;//t为标记从右往左第一个非降序排列
while(--t >= 0){
if(nums[t] < nums[t + 1]){
break;
}
}
if(t < 0){
Arrays.sort(nums,0,nums.length);
}else{
while(p > t){
if(nums[t] >= nums[p]){
p--;
}else{
break;
}
}
temp = nums[p];
nums[p] = nums[t];
nums[t] = temp;
Arrays.sort(nums,t+1,nums.length);
}
}
}
LeetCode32 最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
class Solution {
public int longestValidParentheses(String s) {
if(s == null || s.length() == 0 || s.length() == 1){
return 0;
}
int[] dp = new int [s.length()];
int max = 0;
for(int i = 1;i < s.length();i++){
if(s.charAt(i) == '('){
dp[i] = 0;
}else if(s.charAt(i-1) == '('){
dp[i] = i == 1 ? 2 : dp[i-2] + 2;
}else if(i-1-dp[i-1] >= 0 && s.charAt(i-1-dp[i-1]) == '('){
dp[i] = dp[i-1] + 2 + (i-2-dp[i-1] >= 0 ? dp[i-2-dp[i-1]] : 0);
}
max = max > dp[i] ? max : dp[i];
}
return max;
}
}
LeetCode33 搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
class Solution {
public int search(int[] nums, int target) {
if(nums == null || nums.length == 0){
return -1;
}
int left = 0,right = nums.length - 1,mid;
while(right >= left){
mid = (left + right) / 2;
if(nums[mid] == target){
return mid;
}
if(nums[mid] > nums[nums.length-1]){
if(target < nums[mid] && target > nums[nums.length-1]){
right = mid - 1;
}else{
left = mid + 1;
}
}else{
if(target > nums[mid] && (target < nums[0] || nums[nums.length-1] > nums[0])){
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}
}
LeetCode34 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位
置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
class Solution {
public int[] searchRange(int[] nums, int target) {
if(nums == null || nums.length == 0){
return new int[]{-1,-1};
}
int left = 0,right = nums.length - 1,midLeft = (left + right) / 2,midRight = midLeft;
while(right >= left){
midLeft = (left + right) / 2;
if(nums[midLeft] == target){
if(midLeft == 0 || nums[midLeft-1] != target){
break;
}
right = midLeft - 1;
}else if(nums[midLeft] > target){
right = midLeft - 1;
}else{
left = midLeft + 1;
}
}
left = midLeft;
right = nums.length - 1;
while(right >= left){
midRight = (left + right) / 2;
if(nums[midRight] == target){
if(midRight == nums.length - 1 || nums[midRight+1] != target){
break;
}
left = midRight + 1;
}else if(nums[midRight] > target){
right = midRight - 1;
}else{
left = midRight + 1;
}
}
if(nums[midLeft] != target){
return new int[]{-1,-1};
}
return new int[]{midLeft,midRight};
}
}
LeetCode35 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
class Solution {
public int searchInsert(int[] nums, int target) {
if(nums == null || nums.length == 0){
return 0;
}
int left = 0,right = nums.length - 1,mid = (left + right) / 2;
while(right >= left){
mid = (left + right) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
right = mid - 1;
}else{
left = mid + 1;
}
}
return left;
}
}
LeetCode36 有效的数独
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true
示例 2:
输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
说明:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
给定数独序列只包含数字 1-9 和字符 ‘.’ 。
给定数独永远是 9x9 形式的。
class Solution {
public boolean isValidSudoku(char[][] board) {
boolean[][] line = new boolean[9][9];
boolean[][] col = new boolean[9][9];
boolean[][] palace = new boolean[9][9];
int num;
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
if('.' == board[i][j]){
continue;
}
num = board[i][j] - '1';
if(line[i][num] || col[j][num] || palace[i/3+j/3*3][num]){
return false;
}
line[i][num] = true;
col[j][num] = true;
palace[i/3+j/3*3][num] = true;
}
}
return true;
}
}
LeetCode37 解数独
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
一个数独。
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
class Solution {
public void solveSudoku(char[][] board) {
boolean[][] box = new boolean [9][9];
boolean[][] col = new boolean [9][9];
boolean[][] palace = new boolean [9][9];
int num;
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
if('.' != board[i][j]){
num = board[i][j] - '1';
box[i][num] = true;
col[j][num] = true;
palace[i/3+j/3*3][num] = true;
}
}
}
dfs(board,box,col,palace,0,0);//回溯
}
private boolean dfs(char[][] board,boolean[][] box,boolean[][] col,boolean[][] palace,int i,int j){
while('.' != board[i][j]){//寻找第一个没有数字的节点
j++;
if(j >= 9){
i++;
j = 0;
}
if(i >= 9){
return true;
}
}
for(int k = 0;k < 9;k++){
if(box[i][k] || col[j][k] || palace[i/3+j/3*3][k]){
continue;
}
box[i][k] = true;
col[j][k] = true;
palace[i/3+j/3*3][k] = true;
board[i][j] = (char)(k + '1');
if(dfs(board,box,col,palace,i,j)){
return true;
}else{
box[i][k] = false;
col[j][k] = false;
palace[i/3+j/3*3][k] = false;
board[i][j] = '.';
}
}
return false;
}
}
LeetCode38 报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1 1
2 11
3 21
4 1211
5 111221
1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
输入: 1
输出: “1”
示例 2:
输入: 4
输出: “1211”
class Solution {
public String countAndSay(int n) {
String s = "1";
char u;
StringBuffer p;
int num = 0;
while(--n != 0){
u = s.charAt(0);
num = 1;
p = new StringBuffer();
for(int i = 1;i < s.length();i++){
if(s.charAt(i) != u){
p.append(num).append(u);
u = s.charAt(i);
num = 1;
}else{
num++;
}
}
p.append(num).append(u);
s = p.toString();
}
return s;
}
}
LeetCode39 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
Arrays.sort(candidates);
dfs(list,new ArrayList<Integer>(),candidates,target,0);
return list;
}
private void dfs(List<List<Integer>> list,List<Integer> myList,int[] candidates,int target,int i){
if(target < 0){
return ;
}else if(target == 0){
list.add(new ArrayList<>(myList));
return ;
}
for(int j = i;j < candidates.length;j++){
if(target < candidates[j]){
break;
}
myList.add(candidates[j]);
dfs(list,myList,candidates,target-candidates[j],j);
myList.remove((Integer)candidates[j]);
}
return ;
}
}
LeetCode40 组合总和 II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
Arrays.sort(candidates);
dfs(list,new ArrayList<Integer>(),candidates,target,0);
return list;
}
private void dfs(List<List<Integer>> list,List<Integer> myList,int[] candidates,int target,int i){
if(target < 0){
return ;
}else if(target == 0){
list.add(new ArrayList<>(myList));
return ;
}
for(int j = i;j < candidates.length;j++){
if(target < candidates[j]){
break;
}
if(j > i && candidates[j] == candidates[j-1]){
continue;
}
myList.add(candidates[j]);
dfs(list,myList,candidates,target-candidates[j],j+1);
myList.remove((Integer)candidates[j]);
}
return ;
}
}