leetcode剑指offer2
剑指 Offer 12. 矩阵中的路径
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
class Solution {
public:
bool vis[201][201];
int m,n;
int length;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
bool flag;
bool isOk(int x,int y){
if(x<0||x>=m)return 0;
if(y<0||y>=n)return 0;
return vis[x][y]==0;
}
void dfs(int x,int y,int dep,vector<vector<char>>& board, string word){
if(dep>=length){
flag=1;
return;
}
if(flag)return;///!!!!
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(!isOk(nx,ny))continue;
if(board[nx][ny]==word[dep]){
vis[nx][ny]=1;
dfs(nx,ny,dep+1,board,word);
vis[nx][ny]=0;
}
}
}
bool exist(vector<vector<char>>& board, string word) {
m=board.size(), n=board[0].size();
length=word.length();
flag=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(board[i][j]==word[0]){
vis[i][j]=1;
dfs(i,j,1,board,word);
vis[i][j]=0;
}
if(flag)return 1;
}
}
return 0;
}
};
- dfs搜索,对4个方向进行搜索
- 注意剪枝,找到即返回,if(flag)return,否则会超时
- 时间复杂度 O(3^K MN)
方案数计算: 设字符串长度为 K ,搜索中每个字符有上、下、左、右四个方向可以选择,舍弃回头(上个字符)的方向,剩下 3 种选择,因此方案数的复杂度为 O(3^K) - vector<vector> vis(m,vector(n,false));//记录访没访问过
剑指 Offer 13. 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
class Solution {
private:
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int num;
int count(int x){
int res=0;
while(x>0){
res+=x%10;
x=x/10;
}
return res;
}
void dfs(int x,int y,int m,int n,int k,vector<vector<bool>> &vis){
if(x<0||x>=m||y<0||y>=n||vis[x][y])return;
if(count(x)+count(y)>k)return;
vis[x][y]=1;
num++;
if(num>=m*n)return;
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
dfs(nx,ny,m,n,k,vis);
}
}
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> vis(m,vector<bool>(n,0));
num=0;
dfs(0,0,m,n,k,vis);
return num;
}
};
- 和12题差不多,但是不需要将vis处理为false
- 时间复杂度O(mn)
剑指 Offer 14- I. 剪绳子
给你一根长度为 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。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
class Solution {
public:
int cuttingRope(int n) {
int i,j;
vector<int> dp(n+1,0);
dp[1]=1;
dp[2]=1;
for(i=3;i<=n;i++){
for(j=1;j<i;j++){
dp[i]=max(dp[i],max(dp[j],j)*max(dp[i-j],i-j));
}
}
return dp[n];
}
};
- 动态规划,明显这题具有最优子结构,时间复杂的为O(n^2)
- 贪心① 当所有绳段长度相等时,乘积最大。② 最优的绳段长度为 3 。时间复杂度为O(n)
贪心算法:
int cuttingRope(int n) {
return n <= 3? n - 1 : pow(3, n / 3) * 4 / (4 - n % 3);
}
class Solution:
def cuttingRope(self, n: int) -> int:
if n < 4:
return n - 1
res = 1
while n > 4:
res *=3
n -= 3
return res * n
作者:edelweisskoko
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/jian-zhi-offer-14-i-jian-sheng-zi-huan-s-xopj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
步骤如下:
如果 n == 2,返回1,如果 n == 3,返回2,两个可以合并成n小于4的时候返回n - 1
如果 n == 4,返回4
如果 n > 4,分成尽可能多的长度为3的小段,每次循环长度n减去3,乘积res乘以3;最后返回时乘以小于等于4的最后一小段
以上2和3可以合并
剑指 Offer 14- II. 剪绳子 II
给你一根长度为 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。
2 <= n <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof
typedef long long ll;
class Solution {
public:
ll mod=1e9+7;
ll pow(int a,int n){
ll res=1;
if(n==0)return 1;
if(n==1)return a;
res=pow(a,n/2);
res=res*res%mod;
if(n&1)res=res*a%mod;
return res%mod;
}
int cuttingRope(int n) {
ll ans;
if(n<4)ans=n-1;
else{
if(n%3==0)ans=pow(3,n/3);
else if(n%3==1)ans=pow(3,n/3-1)*4%mod;
else ans=pow(3,n/3)*2%mod;
}
return ans;
}
};
- 数据范围扩大,还要余mod,本题涉及 “大数越界的求余问题” 。
- 使用贪心来写,时间复杂度O(logn)
- 动态规划取余会无法比较大小,当然可以最后取余
动态规划:
import java.math.BigInteger;
class Solution {
public int cuttingRope(int n) {
BigInteger[] dp = new BigInteger[n + 1];
Arrays.fill(dp, BigInteger.valueOf(1));
// dp[1] = BigInteger.valueOf(1);
for(int i = 3; i < n + 1; i++){
for(int j = 1; j < i; j++){
dp[i] = dp[i].max(BigInteger.valueOf(j * (i - j))).max(dp[i - j].multiply(BigInteger.valueOf(j)));
}
}
return dp[n].mod(BigInteger.valueOf(1000000007)).intValue();
}
}
作者:ollieq
链接:https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/solution/jian-dan-li-jie-dong-tai-gui-hua-xun-hua-4g3o/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
技巧:先暴力搜索先找规律
class Solution {
public:
void dfs(int n, long sum, long multi, long& ans) {
if (sum == n) {
ans = max(ans, multi);
return;
} else if (sum > n) {
return;
}
for (long i = 1; i < n; i++) {
dfs(n, i+sum, i*multi, ans);
}
return;
}
int cuttingRope(int n) {
long ans = 0;
dfs(n, 0, 1, ans);
return ans;
}
};
//--->
n 乘积 子数字
2 1 1 1
3 2 1 2
4 4 2 2
5 6 2 3
6 9 3 3
7 12 2 2 3
8 18 2 3 3
9 27 3 3 3
10 36 2 2 3 3
11 54 2 3 3 3
12 81 3 3 3 3
13 108 2 2 3 3 3
14 162 2 3 3 3 3
15 243 3 3 3 3 3
16 324 2 2 3 3 3 3
17 486 2 3 3 3 3 3
18 729 3 3 3 3 3 3
19 972 2 2 3 3 3 3 3
20 1458 2 3 3 3 3 3 3
21 2187 3 3 3 3 3 3 3
22 2916 2 2 3 3 3 3 3 3
23 4374 2 3 3 3 3 3 3 3
24 6561 3 3 3 3 3 3 3 3
25 8748 2 2 3 3 3 3 3 3 3
26 13122 2 3 3 3 3 3 3 3 3
27 19683 3 3 3 3 3 3 3 3 3
28 26244 2 2 3 3 3 3 3 3 3 3
29 39366 2 3 3 3 3 3 3 3 3 3