leetcode刷题笔记(8)
(1)9. 回文数
思路1:负数一定为false,小于10的正数一定为true,个位为0的数一定为false,然后将数字转化为string进行判断。
class Solution {
public boolean isPalindrome(int x) {
if(x < 0){
return false;
}
if(x < 10){
return true;
}
if(x % 10 == 0){
return false;
}
String str = String.valueOf(x);
return strPalidrome(str);
}
public boolean strPalidrome(String str){
if(str.length() <= 1){
return true;
}
if(str.charAt(0) == str.charAt(str.length()-1)){
if(str.length()==2){
return true;
}else{
return strPalidrome(str.substring(1,str.length()-1));
}
}
return false;
}
}
思路2:获得x的逆序数字,判断是否与x相等。
class Solution {
public boolean isPalindrome(int x) {
if(x < 0){
return false;
}
int temp = 0;
int y = 0;
int num = x;
while(num > 0){
temp = num % 10;
y = y * 10 + temp;
num = num / 10;
}
return x == y;
}
}
(2)29. 两数相除
思路:使用位运算。
class Solution {
public int divide(int dividend, int divisor) {
if (dividend == 0) {
return 0;
}
if (dividend == Integer.MIN_VALUE && divisor == -1) {
return Integer.MAX_VALUE;
}
boolean negative;
negative = (dividend ^ divisor) <0;//用异或来计算是否符号相异
long t = Math.abs((long) dividend);
long d= Math.abs((long) divisor);
int result = 0;
for (int i=31; i>=0;i--) {
if ((t>>i)>=d) {//找出足够大的数2^n*divisor
result+=1<<i;//将结果加上2^n
t-=d<<i;//将被除数减去2^n*divisor
}
}
return negative ? -result : result;//符号相异取反
}
}
(3)46. 全排列(错1)
题解思路:动态规划,使用一个数组存储是否遍历到该数字。
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
int[] visited = new int[nums.length];
childPermute(res, nums,new ArrayList<Integer>(),visited);
return res;
}
public void childPermute(List<List<Integer>> res,int[] nums, List<Integer> temp, int[] visited){
if(temp.size() == nums.length){
res.add(new ArrayList<>(temp));
return;
}
for(int i = 0; i < nums.length; i++){
if(visited[i] == 1){
continue;
}else{
visited[i] = 1;
temp.add(nums[i]);
childPermute(res, nums, temp, visited);
visited[i] = 0;
temp.remove(temp.size()-1);
}
}
}
}
(4)131. 分割回文串(错1)
题解思路1:回溯+动态规划,
class Solution {
boolean[][] f;
List<List<String>> ret = new ArrayList<List<String>>();
List<String> ans = new ArrayList<String>();
int n;
public List<List<String>> partition(String s) {
n = s.length();
f = new boolean[n][n];
for (int i = 0; i < n; ++i) {
Arrays.fill(f[i], true);
}
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
f[i][j] = (s.charAt(i) == s.charAt(j)) && f[i + 1][j - 1];
}
}
dfs(s, 0);
return ret;
}
public void dfs(String s, int i) {
if (i == n) {
ret.add(new ArrayList<String>(ans));
return;
}
for (int j = i; j < n; ++j) {
if (f[i][j]) {
ans.add(s.substring(i, j + 1));
dfs(s, j + 1);
ans.remove(ans.size() - 1);
}
}
}
}
题解思路2:回溯+记忆化搜索
class Solution {
int[][] f;
List<List<String>> ret = new ArrayList<List<String>>();
List<String> ans = new ArrayList<String>();
int n;
public List<List<String>> partition(String s) {
n = s.length();
f = new int[n][n];
dfs(s, 0);
return ret;
}
public void dfs(String s, int i) {
if (i == n) {
ret.add(new ArrayList<String>(ans));
return;
}
for (int j = i; j < n; ++j) {
if (isPalindrome(s, i, j) == 1) {
ans.add(s.substring(i, j + 1));
dfs(s, j + 1);
ans.remove(ans.size() - 1);
}
}
}
// 记忆化搜索中,f[i][j] = 0 表示未搜索,1 表示是回文串,-1 表示不是回文串
public int isPalindrome(String s, int i, int j) {
if (f[i][j] != 0) {
return f[i][j];
}
if (i >= j) {
f[i][j] = 1;
} else if (s.charAt(i) == s.charAt(j)) {
f[i][j] = isPalindrome(s, i + 1, j - 1);
} else {
f[i][j] = -1;
}
return f[i][j];
}
}
(5)38. 外观数列
思路:使用一个函数生成对前一项数字的描述,for循环逐次生成。
class Solution {
public String countAndSay(int n) {
String str = "1";
if(n == 1){
return str;
}
for(int i = 2; i <= n; i++){
str = transfer(str);
}
return str;
}
public String transfer(String str){
String res = "";
int left = 0;
int right = 1;
char temp = str.charAt(0);
while(right <= str.length()){
while(right < str.length() && str.charAt(right) == temp){
right++;
}
res += (String.valueOf(right - left) + String.valueOf(temp));
if(right < str.length()){
temp = str.charAt(right);
}
left = right;
right++;
}
return res;
}
}
(6)132. 分割回文串 II
class Solution {
public int minCut(String s) {
int n = s.length();
boolean[][] g = new boolean[n][n];
for (int i = 0; i < n; ++i) {
Arrays.fill(g[i], true);
}
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
g[i][j] = s.charAt(i) == s.charAt(j) && g[i + 1][j - 1];
}
}
int[] f = new int[n];
Arrays.fill(f, Integer.MAX_VALUE);
for (int i = 0; i < n; ++i) {
if (g[0][i]) {
f[i] = 0;
} else {
for (int j = 0; j < i; ++j) {
if (g[j + 1][i]) {
f[i] = Math.min(f[i], f[j] + 1);
}
}
}
}
return f[n - 1];
}
}
(7)59. 螺旋矩阵 II
思路:模拟,flag表示当前方向,对于每种方向而言,发生转向所转的方向是固定的,故只需考虑到各种发生转向的情形。
class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
if(n == 1){
matrix[0][0] = 1;
return matrix;
}
int flag = 1;
int cur = 1;
int i = 0;
int j = 0;
while(cur <= n*n){
matrix[i][j] = cur;
cur++;
if(flag == 1){
if(j < n-1 && matrix[i][j+1] == 0){
j++;
}else{
if(matrix[i+1][j] == 0){
flag = 2;
i++;
}else{
break;
}
}
}else if(flag == 2){
if(i < n-1 && matrix[i+1][j] == 0){
i++;
}else{
if(matrix[i][j-1] == 0){
flag = 3;
j--;
}else{
break;
}
}
}else if(flag == 3){
if(j > 0 && matrix[i][j-1] == 0){
j--;
}else{
if(matrix[i-1][j] == 0){
flag = 4;
i--;
}else{
break;
}
}
}else{
if(i > 0 && matrix[i-1][j] == 0){
i--;
}else{
if(matrix[i][j+1] == 0){
flag = 1;
j++;
}else{
break;
}
}
}
}
return matrix;
}
}
思路2:
class Solution {
public int[][] generateMatrix(int n) {
int ub = 0;
int lb = n-1;
int left = 0;
int right = n-1;
int[][] matrix = new int[n][n];
int cur = 1;
while(cur <= n*n){
if(ub <= lb){
for(int i = left; i <= right; i++){
matrix[ub][i] = cur;
cur++;
}
ub++;
}
if(left <= right){
for(int i = ub; i <= lb; i++){
matrix[i][right] = cur;
cur++;
}
right--;
}
if(ub <= lb){
for(int i = right; i >= left; i--){
matrix[lb][i] = cur;
cur++;
}
lb--;
}
if(left <= right){
for(int i = lb; i >= ub; i--){
matrix[i][left] = cur;
cur++;
}
left++;
}
}
return matrix;
}
}
(8)48. 旋转图像
思路:先将矩阵对称,再对矩阵的每一行进行reverse。
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
int temp;
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
for(int i = 0; i < n; i++){
int left = 0;
int right = n-1;
while(left < right){
temp = matrix[i][left];
matrix[i][left] = matrix[i][right];
matrix[i][right] = temp;
left++;
right--;
}
}
}
}
(9)54. 螺旋矩阵
思路1:模拟,flag表示当前方向,对于每种方向而言,发生转向所转的方向是固定的,故只需考虑到各种发生转向的情形。对于已经遍历过的位置,将其置为不可能的数,用以标记。
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
List<Integer> res = new ArrayList<Integer>();
if(n == 1 && m == 1){
res.add(matrix[0][0]);
return res;
}
int flag = 1;
int count = 1;
int i = 0;
int j = 0;
while(count <= n*m){
res.add(matrix[i][j]);
matrix[i][j] = 1000;
count++;
if(flag == 1){
if(j < m-1 && matrix[i][j+1] != 1000){
j++;
}else{
if(i < n-1 && matrix[i+1][j] != 1000){
flag = 2;
i++;
}else{
break;
}
}
}else if(flag == 2){
if(i < n-1 && matrix[i+1][j] != 1000){
i++;
}else{
if(j > 0 && matrix[i][j-1] != 1000){
flag = 3;
j--;
}else{
break;
}
}
}else if(flag == 3){
if(j > 0 && matrix[i][j-1] != 1000){
j--;
}else{
if(i > 0 && matrix[i-1][j] != 1000){
flag = 4;
i--;
}else{
break;
}
}
}else{
if(i > 0 && matrix[i-1][j] != 1000){
i--;
}else{
if(j < m-1 && matrix[i][j+1] != 1000){
flag = 1;
j++;
}else{
break;
}
}
}
}
return res;
}
}
思路2:方向变化的规律是一致的,故可以不需要对方向进行标记,在进行遍历的过程中,不断缩小矩阵的范围。
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
int up = 0;
int down = n-1;
int left = 0;
int right = m-1;
List<Integer> res = new ArrayList<Integer>();
int count = 0;
while(count < n*m){
if(up <= down){
for(int i = left; i <= right; i++){
res.add(matrix[up][i]);
count++;
}
up++;
}
if(left <= right){
for(int i = up; i <= down; i++){
res.add(matrix[i][right]);
count++;
}
right--;
}
if(up <= down){
for(int i = right; i >= left; i--){
res.add(matrix[down][i]);
count++;
}
down--;
}
if(left <= right){
for(int i = down; i >= up; i--){
res.add(matrix[i][left]);
count++;
}
left++;
}
}
return res;
}
}
(10)1288. 删除被覆盖区间
思路:两两区间进行比较,使用一个数组记录是否被删除,遍历完成后,统计没有被删除的数组数量。
class Solution {
public int removeCoveredIntervals(int[][] intervals) {
int n = intervals.length;
int[] deleted = new int[n];
for(int i = 0; i < n; i++){
for(int j = i+1; j < n; j++){
if(deleted[i] == 0 && deleted[j] == 0){
int[] temp1 = intervals[i];
int[] temp2 = intervals[j];
if(temp1[0] <= temp2[0] && temp1[1] >= temp2[1]){
deleted[j] = 1;
}else if(temp1[0] >= temp2[0] && temp1[1] <= temp2[1]){
deleted[i] = 1;
}
}
}
}
int res = 0;
for(int i = 0; i < n; i++){
if(deleted[i] == 0){
res++;
}
}
return res;
}
}
思路2:贪心算法,
class Solution {
public int removeCoveredIntervals(int[][] intervals) {
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] == o2[0] ? o2[1] - o1[1]: o1[0] - o2[0];
}
});
int count = 0;
int end, prev_end = 0;
for (int[] curr : intervals) {
end = curr[1];
if (prev_end < end) {
++count;
prev_end = end;
}
}
return count;
}
}