47.在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
提示:
0 < grid.length <= 200
0 < grid[0].length <= 200
修改数组搞一哈
class Solution {
public int maxValue(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
for(int i=1;i<m;i++){
grid[i][0]+=grid[i-1][0];
}
for(int i=1;i<n;i++){
grid[0][i]+=grid[0][i-1];
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
grid[i][j]=Math.max(grid[i-1][j],grid[i][j-1])+grid[i][j];
}
}
return grid[m-1][n-1];
}
}
27.请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/ \
2 7
/ \ / \
1 3 6 9
镜像输出:4
/ \
7 2
/ \ / \
9 6 3 1示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
限制:
0 <= 节点个数 <= 1000
注意:本题与主站 226 题相同:https://leetcode-cn.com/problems/invert-binary-tree/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
//递归
TreeNode temp=root;
if(temp==null){
return root;
}
//否则交换左右子树
TreeNode t=temp.left;
temp.left=temp.right;
temp.right=t;
mirrorTree(temp.left);
mirrorTree(temp.right);
return root;
}
}
搞个辅助栈看看。
class Solution {
public TreeNode mirrorTree(TreeNode root) {
Stack<TreeNode> stack=new Stack<>();
if(root==null){
return null;
}
TreeNode temp=root;
stack.push(temp);
while(!stack.isEmpty()){
//先弹出一个当前结点
TreeNode t=stack.pop();
//压入当前结点的左右节点
if(t.right!=null){
stack.push(t.right);
}
if(t.left!=null){
stack.push(t.left);
}
//将当前节点的左右节点交换
TreeNode n=t.left;
t.left=t.right;
t.right=n;
}
return root;
}
}
主要过程就是先压根节点,每个结点都被访问到,对每个结点的左右节点进行交换,每个结点是通过栈顶访问的。
28.请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:1
/ \
2 2
\ \
3 3示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:输入:root = [1,2,2,null,3,null,3]
输出:false
限制:
0 <= 节点个数 <= 1000
注意:本题与主站 101 题相同:https://leetcode-cn.com/problems/symmetric-tree/
迭代双栈
class Solution {
public boolean isSymmetric(TreeNode root) {
//迭代两个栈
TreeNode temp=root;
if(temp==null){
return true;
}
Stack<TreeNode> left=new Stack<>();
Stack<TreeNode> right=new Stack<>();
left.push(temp);
right.push(temp);
while(!left.isEmpty()&&!right.isEmpty()){
TreeNode t1=left.pop();
TreeNode t2=right.pop();
if(t1.val!=t2.val){
return false;
}
if(t1.left!=null&&t2.right!=null){
left.push(t1.left);
right.push(t2.right);
}else if(t1.left==null&&t2.right==null){
}else{
return false;
}
if(t1.right!=null&&t2.left!=null){
left.push(t1.right);
right.push(t2.left);
}else if(t1.right==null&&t2.left==null){
}else{
return false;
}
}
if(left.isEmpty()&&right.isEmpty()){
return true;
}else{
return false;
}
}
}
递归还是牛的
class Solution {
public boolean isSymmetric(TreeNode root) {
//递归
if(root==null){
return true;
}else{
return func(root.left,root.right);
}
}
public boolean func(TreeNode l,TreeNode r){
if(r==null&&l==null){
return true;
}else if(l!=null&&r!=null&&l.val==r.val){
return func(l.left,r.right)&&func(l.right,r.left);
}else{
return false;
}
}
}
29.输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
限制:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100
注意:本题与主站 54 题相同:https://leetcode-cn.com/problems/spiral-matrix/
嘿嘿 自己写出来了耶
class Solution {
public int[] spiralOrder(int[][] matrix) {
int m=matrix.length;
if(m==0){
return new int[0];
}
int n=matrix[0].length;
int[] res=new int[m*n];
boolean[][] flag=new boolean[m][n];
int x=0;
int y=0;
int index=0;
res[0]=matrix[0][0];
flag[0][0]=true;
//在上下左右都行不通的时候,退出循环
while(index!=m*n-1){
while(y+1<n&&flag[x][y+1]!=true){
y++;
index++;
flag[x][y]=true;
res[index]=matrix[x][y];
}
while(x+1<m&&flag[x+1][y]!=true){
x++;
index++;
flag[x][y]=true;
res[index]=matrix[x][y];
}
while(y-1>=0&&flag[x][y-1]!=true){
y--;
index++;
flag[x][y]=true;
res[index]=matrix[x][y];
}
while(x-1>=0&&flag[x-1][y]!=true){
x--;
index++;
flag[x][y]=true;
res[index]=matrix[x][y];
}
}
return res;
}
}
有没有一种可能不需要额外的空间呢?
一层一层的打印?
class Solution {
public int[] spiralOrder(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return new int[0];
}
int rows = matrix.length, columns = matrix[0].length;
int[] order = new int[rows * columns];
int index = 0;
int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
while (left <= right && top <= bottom) {
for (int column = left; column <= right; column++) {
order[index++] = matrix[top][column];
}
for (int row = top + 1; row <= bottom; row++) {
order[index++] = matrix[row][right];
}
if (left < right && top < bottom) {
for (int column = right - 1; column > left; column--) {
order[index++] = matrix[bottom][column];
}
for (int row = bottom; row > top; row--) {
order[index++] = matrix[row][left];
}
}
left++;
right--;
top++;
bottom--;
}
return order;
}
}
19.请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:输入:
s = "ab"
p = ".*"
输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:输入:
s = "aab"
p = "c*a*b"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:输入:
s = "mississippi"
p = "mis*is*p*."
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。
二刷了属于是
class Solution {
public boolean isMatch(String s, String p) {
//动态规划,f[i][j]表示s的前i个字符可以与p的前j个字符是否相匹配
//如果p[j]是普通字符,且s[i]==p[j],那么f[i][j]=f[i-1][j-1]
//如果P[j]是.,那么f[i][j]=f[i-1][j-1]
//如果p[j]是*,如果P[j-1]==s[i],f[i][j]=f[i][j-2]||f[i-1][j],如果不匹配,f[i][j]=f[i][j-2]
int m=s.length();
int n=p.length();
//第i个实际上是在字符串里是i-1,但boolean数组人为加了一个0,0,所以里面是i
boolean[][] res=new boolean[m+1][n+1];
res[0][0]=true;
for(int i=0;i<=m;i++){
for(int j=1;j<=n;j++){
if(p.charAt(j-1)=='*'){
if(match(s,p,i,j-1)){
//又忘了!!也有可能是多余的,如果多余可以,不必退
res[i][j]=res[i][j-2]||res[i-1][j];
}else{
res[i][j]=res[i][j-2];
}
}else{
if(match(s,p,i,j)){
res[i][j]=res[i-1][j-1];
}
}
}
}
return res[m][n];
}
public boolean match(String s,String p,int i,int j){
//其实没有第0个字符
if(i==0){
return false;
}
if(p.charAt(j-1)=='.'){
return true;
}
return s.charAt(i-1)==p.charAt(j-1);
}
}
12.给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在下面的 3×4 的矩阵中包含单词 "ABCCED"(单词中的字母已标出)。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:输入:board = [["a","b"],["c","d"]], word = "abcd"
输出:false
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成
注意:本题与主站 79 题相同:https://leetcode-cn.com/problems/word-search/
注意点在于:必须把k==length写在最前面!!!
class Solution {
public boolean exist(char[][] board, String word) {
//回溯
int m=board.length;
int n=board[0].length;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(check(board,word,i,j,0)){
return true;
}
}
}
return false;
}
public boolean check(char[][] board,String word,int x,int y,int k){
int m=board.length;
int n=board[0].length;
int length=word.length();
if(k==length){
return true;
}
if(x<0||x>=m||y<0||y>=n){
return false;
}
if(board[x][y]!=word.charAt(k)){
return false;
}
char temp=board[x][y];
board[x][y]='0';
boolean res=check(board,word,x-1,y,k+1)||check(board,word,x+1,y,k+1)||check(board,word,x,y+1,k+1)||check(board,word,x,y-1,k+1);
board[x][y]=temp;
return res;
}
}
14.给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]*k[1]*...*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 1000
注意:本题与主站 343 题相同:https://leetcode-cn.com/problems/integer-break/
注意越界问题,数学解法:
class Solution {
public int cuttingRope(int n) {
if(n==2){return 1;}
if(n==3){return 2;}
int k=n/3;
int a=n%3;
if(a==1){
k--;
a+=3;
}else if(a==0){
a=1;
}
//直接存储结果double也会越界
long res=1;
while(k!=0){
res*=3;
k--;
if(res>1000000007){
res%=1000000007;
}
}
res*=a;
if(res>1000000007){
res%=1000000007;
}
return (int)res;
}
}
优化求结果部分,使用位运算?
class Solution {
public int cuttingRope(int n) {
if(n==2){return 1;}
if(n==3){return 2;}
int k=n/3;
int a=n%3;
if(a==1){
k--;
a+=3;
}else if(a==0){
a=1;
}
//直接存储结果double也会越界
long res=1;
long temp=3;
while(k!=0){
// res*=3;
// k--;
// if(res>1000000007){
// res%=1000000007;
// }
//进行优化
if((k&1)==1){
res*=temp;
res%=1000000007;
}
temp*=temp;
temp%=1000000007;
k>>=1;
}
res*=a;
if(res>1000000007){
res%=1000000007;
}
return (int)res;
}
}
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
示例 1:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。
提示:
0 <= pushed.length == popped.length <= 1000
0 <= pushed[i], popped[i] < 1000
pushed 是 popped 的排列。
注意:本题与主站 946 题相同:https://leetcode-cn.com/problems/validate-stack-sequences/
用栈来模拟,遍历push数组,只要栈顶元素和pop当前元素相等,就弹出,最后判断栈是否为空。
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Stack<Integer> stack=new Stack<>();
int index=0;
for(int p:pushed){
stack.push(p);
while(!stack.isEmpty()&&stack.peek()==popped[index]){
stack.pop();
index++;
}
}
return stack.isEmpty();
}
}
49.我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:1 是丑数。
n 不超过1690。
注意:本题与主站 264 题相同:https://leetcode-cn.com/problems/ugly-number-ii/
class Solution {
public int nthUglyNumber(int n) {
//动态规划来罗
int[] dp=new int[n];
dp[0]=1;
int a=0,b=0,c=0;
int n2;
int n3;
int n5;
for(int i=1;i<n;i++){
n2=dp[a]*2;
n3=dp[b]*3;
n5=dp[c]*5;
dp[i]=Math.min(n2,Math.min(n3,n5));
if(dp[i]==n2){
a++;
}
if(dp[i]==n3){
b++;
}
if(dp[i]==n5){
c++;
}
}
return dp[n-1];
}
}
56.一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums.length <= 10000
class Solution {
public int[] singleNumbers(int[] nums) {
//思路:对整个数组进行异或,得到的结果就是两个只出现一次的数字的抑或结果。
//找结果中的一位为1的位,并按这个位将数组分成两个。
//然后对两个数组进行全异或,结果为只出现过一次的数字。
int n=nums.length;
int res=nums[0];
for(int i=1;i<n;i++){
res^=nums[i];
}
int count=0;
while((res&1)==0){
res>>=1;
count++;
}
int res1=0;
int res2=0;
for(int i=0;i<n;i++){
if(((nums[i]>>count)&1)==1){
res1^=nums[i];
}else{
res2^=nums[i];
}
}
return new int[]{res1,res2};
}
}