31. 下一个排列
class Solution {
public void nextPermutation(int[] nums) {
int len = nums.length, i = len - 1;;
while(i > 0 && nums[i-1] >= nums[i]) --i;
if(i <= 0) {
reverse(nums, 0, len - 1);
}else {
int t = i;
while(t < len && nums[t] > nums[i-1]) ++t;
swap(nums, i - 1, t-1);
reverse(nums, i, len - 1);
}
}
private void swap(int nums[], int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
private void reverse(int nums[], int i, int j) {
if(i < 0 || i >= nums.length || j < 0 ||j >= nums.length|| j < i)return;
while(i < j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
++i;
--j;
}
}
}
32. 最长有效括号
class Solution {
//有效括号两特性:1.左括号数大于右括号数;2.左右括号数相等的时候有效括号最长
/*
分段:按照左括号>=右括号分段,当左括号 < 右括号的时候,前一个字符进行分段为前一段最后一个字符。
把s字符串分为若干段的有效括号段;s=s1s2s3..sn,每段最长有效括号在每段内,不会跨段,即有效括号不会再si sj之间。
反证法:假设跨段pi..pj其中pi再si段中到sj段中的pj之间为有效括号,A段[lsi,...si...rsi]
和B段[lsj...sj...rsj],根据有效括号性质
跨段符合有效括号性质[si...sj]之间左前缀,左括号数 >= 右括号数
==>[si...lsj]之间左括号数 >= 右括号数
在A段,左前缀[lsi..si-1]之间左括号数>= 右括号数
所以[lsi..si-1,si...lsj]之间左括号数>= 右括号数 ①
而按照分段原理[lsi...lsj]之间左括号数 < 右括号数,与①矛盾,所以不肯能跨段为有效括号。
*/
public int longestValidParentheses1(String s) {
Stack<Integer> stk = new Stack<>();
char cs[] = s.toCharArray();
int ans = 0;
//start为分割,上段有效括号的分割点
for(int i = 0, start = -1; i < cs.length; i++) {
if(cs[i] == ')') {
if(!stk.isEmpty()){
stk.pop();
if(!stk.isEmpty()) {
ans = Math.max(ans, i - stk.peek());
}else{
ans = Math.max(ans, i - start);
}
}else {
start = i;
}
}else {
//'('
stk.push(i);
}
}
return ans;
}
}
33. 搜索旋转排序数组
class Solution {
public int search(int[] nums, int target) {
int l = 0, r = nums.length - 1;
//两段递增区间,找出第一段递归区间的最后一个元素的下标,分为两个区间[0, r] [r + 1, nums.length - 1]
while(l < r) {
int mid = (l + r + 1) >> 1;
if(nums[mid] >= nums[0]) l = mid;
else r = mid - 1;
}
//判断target在那一段递增区间中
if(target >= nums[0]) l = 0; //在[0,r]区间中
else {//在[r+1, nums.length - 1]
l = r + 1;
r = nums.length - 1;
}
//再一次递归查找
while(l < r) {
int mid = (l + r) >> 1;
if(nums[mid] >= target) r = mid;
else l = mid + 1;
}
return nums[r] == target? l : -1;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
//二分查找
public int[] searchRange(int[] nums, int target) {
if(nums.length == 0) return new int[]{-1, -1};
int l = 0, r = nums.length - 1;
while(l < r) {
int mid = (l + r) >> 1;
if(nums[mid] >= target) r = mid;
else l = mid + 1;
}
if(nums[l] != target) {
return new int[]{-1, -1};
}else {
int tmp = l;
l = 0;
r = nums.length - 1;
while(l < r) {
int mid = (l + r + 1) >> 1;
if(nums[mid] <= target) l = mid;
else r = mid - 1;
}
return new int[]{tmp, l};
}
}
}
35. 搜索插入位置
class Solution {
//二分查找
public int searchInsert1(int[] nums, int target) {
int l = 0, r = nums.length - 1;
while(l < r) {
int mid = (l + r) >> 1;
if(nums[mid] >= target) r = mid;
else l = mid + 1;
}
if(nums[l] < target) return nums.length;
return l;
}
//二分查找
public int searchInsert(int[] nums, int target) {
int l = 0, r = nums.length;
while(l < r) { //l小于r
int mid = (l + r) >> 1; //那么mid严格小于nums.length
if(nums[mid] >= target) r = mid; //
else l = mid + 1;
}
// if(nums[r] < target) return nums.length;
return l;
}
}
36. 有效的数独
class Solution {
public boolean isValidSudoku(char[][] board) {
boolean st[] = new boolean[9];
//判断行
for(int i = 0; i< 9; i++) {
Arrays.fill(st, false);
for(int j = 0; j < 9; j++) {
if(board[i][j]!='.') {
int num = board[i][j] - '1';
if(st[num] == true) {
return false;
}else {
st[num] = true;
}
}
}
}
//判断列
for(int i = 0; i< 9; i++) {
Arrays.fill(st, false);
for(int j = 0; j < 9; j++) {
if(board[j][i]!='.') {
int num = board[j][i] - '1';
if(st[num] == true) {
return false;
}else {
st[num] = true;
}
}
}
}
//判断小方格
for(int i = 0; i < 9; i+= 3){
for(int j = 0; j < 9; j += 3) {
Arrays.fill(st, false);
for(int x = 0; x < 3; x++) {
for(int y = 0; y < 3; y++) {
if(board[i + x][j + y]!='.') {
int num = board[i + x][j + y] - '1';
if(st[num] == true) return false;
else st[num] = true;
}
}
}
}
}
return true;
}
}
37. 解数独
class Solution {
boolean row[][] = new boolean[9][9], //每一行1到9是否存在
col[][] = new boolean[9][9],//每一列1到9是否存在
cell[][][] = new boolean[3][3][9];//每个小方格1到9是否存在
//爆搜
public void solveSudoku(char[][] board) {
//初始化状态
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(board[i][j] != '.') {
int num = board[i][j] - '1';
row[i][num] = col[j][num] = cell[i/3][j/3][num] = true;
}
}
}
//爆搜从左上角开始爆搜
dfs(board, 0, 0);
}
private boolean dfs(char[][] board, int x, int y) {
if(y == 9){++x; y = 0;}
if(x == 9) return true;
if(board[x][y]!='.') return dfs(board, x, y + 1);//跳到下一个
for(int i = 0; i < 9; i++) {
if(!row[x][i] && ! col[y][i] && !cell[x/3][y/3][i]) {
row[x][i] = col[y][i] = cell[x/3][y/3][i] = true;
board[x][y] = (char)(i + '1');
if(dfs(board, x, y + 1)) return true;
board[x][y] = '.';
row[x][i] = col[y][i] = cell[x/3][y/3][i] = false;
}
}
return false;
}
}