泰波那契序列 Tn 定义如下:
T 0 = 0 , T 1 = 1 , T 2 = 1 , 且 在 n > = 0 的 条 件 下 T n + 3 = T n + T n + 1 + T n + 2 T_{0} = 0, T_{1} = 1, T_{2} = 1, 且在 n >= 0 的条件下 T_{n+3} = T{_n} + T_{n+1} + T_{n+2} T0=0,T1=1,T2=1,且在n>=0的条件下Tn+3=Tn+Tn+1+Tn+2
给你整数 n
,请返回第 n 个泰波那契数 T n T_{n} Tn的值。
示例 1:
输入:n = 4
输出:4
解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4
示例 2:
输入:n = 25
输出:1389537
提示:
0 <= n <= 37
answer <= 2^31 - 1
。与求解斐波那契数列的第n项的思路相同,采用递推的方式进行求解。
需要注意的是,答案是一个32位整数,因此需要用unsigned int
存储答案,如果用int
存储,可能会发生越界。
class Solution {
public:
int tribonacci(int n)
{
if(n==0)
return 0;
if(n==1)
return 1;
if(n==2)
return 1;
unsigned int pre=0,mid=1,post=1;
unsigned int ans;
for(int i=3;i<=n;++i)
{
ans=pre+mid+post;
pre=mid;
mid=post;
post=ans;
}
return ans;
}
};
我们从一块字母板上的位置 (0, 0)
出发,该坐标对应的字符为 board[0][0]
。
在本题里,字母板为board = ["abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"]
.
我们可以按下面的指令规则行动:
'U'
意味着将我们的位置上移一行;'D'
意味着将我们的位置下移一行;'L'
意味着将我们的位置左移一列;'R'
意味着将我们的位置右移一列;(r, c)
的字符 board[r][c]
添加到答案中。返回指令序列,用最小的行动次数让答案和目标 target
相同。你可以返回任何达成目标的路径。
示例 1:
输入:target = "leet"
输出:"DDR!UURRR!!DDD!"
示例 2:
输入:target = "code"
输出:"RR!DDRR!UUL!R!"
提示:
1 <= target.length <= 100
target
仅含有小写英文字母。由于仅能上下左右移动,实际上给定单词的指令序列长度是一定的。而且题目中并未规定输出指令的顺序,因此只要明确两个字母间的横向和纵向距离差即可输出相应的指令。
由于字母板最后一行仅有一个字母z
,因此若想移动到z
,仅能从第5行的u
向下移动到z
。若想从z
移动到其他字母,只能先从z
开始向上移动,随后再进行左右移动。因此,若目的地是z
,则先执行左右移动的指令,再执行上下移动的指令;若起点是z
,则先执行左右移动的指令,再执行上下移动的指令。
本题中无需构建出字母板,只需要计算各字母间坐标,求出目标点和起始点之间的坐标的相对大小即可:
int xi = (x - 'a') / 5;
int xj = (x - 'a') % 5;
int curi = (cur - 'a') / 5;
int curj = (cur - 'a') % 5;
deltai = xi - curi;
deltaj = xj - curj;
若偏移量大于0,则执行下/右移动,若偏移量小于0,则执行上/左移动。
char row[2]={'U','D'};
char col[2]={'L','R'};
class Solution {
public:
string alphabetBoardPath(string target)
{
char cur = 'a';
string ans;
int deltai, deltaj;
for (auto x : target)
{
calculate(x, cur,deltai,deltaj);
if (cur == 'z')
{
for (int i = 0; i<abs(deltai); ++i)
ans += row[deltai>0];
for (int j = 0; j<abs(deltaj); ++j)
ans += col[deltaj>0];
}
else
{
for (int j = 0; j<abs(deltaj); ++j)
ans += col[deltaj>0];
for (int i = 0; i<abs(deltai); ++i)
ans += row[deltai>0];
}
ans += '!';
cur = x;
}
return ans;
}
void calculate(char x, char cur, int& deltai, int&deltaj)
{
int xi = (x - 'a') / 5;
int xj = (x - 'a') % 5;
int curi = (cur - 'a') / 5;
int curj = (cur - 'a') % 5;
deltai = xi - curi;
deltaj = xj - curj;
}
};
给你一个由若干 0
和 1
组成的二维网格 grid
,请你找出边界全部由 1
组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0
。
示例 1:
输入:grid = [[1,1,1],[1,0,1],[1,1,1]]
输出:9
示例 2:
输入:grid = [[1,1,0,0]]
输出:1
提示:
1 <= grid.length <= 100
1 <= grid[0].length <= 100
grid[i][j] 为 0 或 1
本题可利用滑动窗口法进行检测。具体过程结合参考代码分析。
class Solution {
public:
int largest1BorderedSquare(vector<vector<int>>& g)
{
int s1[105][105],s2[105][105],ans=0;
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
int n=g.size(),m=g[0].size(),i,j,k;
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
{
s1[i][j]=s1[i][j-1]+g[i-1][j-1];//s1是每行的积累和
s2[i][j]=s2[i-1][j]+g[i-1][j-1];//s2是每列的积累和
}
}
int len=min(m,n);
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
{
for (k=1;i+k-1<=n&&j+k-1<=m;k++)//(i,j)是正方形滑窗的左上角的坐标,k是滑窗大小
{
int l1=i,r1=i+k-1;
int l2=j,r2=j+k-1;
if (k<=ans) continue;//当前边长小于已经获得的边长,则直接跳过
if (s1[l1][r2]-s1[l1][l2-1]!=k) continue;
if (s1[r1][r2]-s1[r1][l2-1]!=k) continue;
if (s2[r1][r2]-s2[l1-1][r2]!=k) continue;
if (s2[r1][l2]-s2[l1-1][l2]!=k) continue;
ans=k;
if(ans==len)
return ans*ans;
}
}
}
return ans*ans;
}
};
分析:
s1和s2分别是每行元素的累积和与每列元素的累积和。若当前行全为1,则累积和的最后一个元素应等于列的数目。
随后进行滑窗检测。滑窗左上角的起始点为(i,j),滑窗的边长为k。根据起点和k可以得出行的起点和终点为[l1,r1],列的起点和终点为[l2,r2]。随后进行5项检测:
亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子 piles[i]
。游戏以谁手中的石子最多来决出胜负。
亚历克斯和李轮流进行,亚历克斯先开始。最初,M = 1
。
在每个玩家的回合中,该玩家可以拿走剩下的 前 X
堆的所有石子,其中 1 <= X <= 2M
。然后,令 M = max(M, X)
。
游戏一直持续到所有石子都被拿走。
假设亚历克斯和李都发挥出最佳水平,返回亚历克斯可以得到的最大数量的石头。
示例:
输入:piles = [2,7,9,4,4]
输出:10
解释:
如果亚历克斯在开始时拿走一堆石子,李拿走两堆,接着亚历克斯也拿走两堆。在这种情况下,亚历克斯可以拿到 2 + 4 + 4 = 10 颗石子。
如果亚历克斯在开始时拿走两堆石子,那么李就可以拿走剩下全部三堆石子。在这种情况下,亚历克斯可以拿到 2 + 7 = 9 颗石子。
所以我们返回更大的 10。
提示:
1 <= piles.length <= 100
1 <= piles[i] <= 10 ^ 4
(暂时不懂)
class Solution {
public:
int stoneGameII(vector<int>& piles)
{
int dp[105][105],s[105],n=piles.size(),i,j,k;
memset(dp,0,sizeof(dp));
memset(s,0,sizeof(s));
for (i=1;i<=n;i++)
s[i]=s[i-1]+piles[i-1];
for (i=n;i>=1;i--)
{
for (j=1;j<=100;j++)
{
for (k=1;i+k-1<=n&&k<=2*j;k++)
dp[i][j]=max(dp[i][j],s[n]-s[i-1]-dp[i+k][min(100,max(j,k))]);
}
}
return dp[1][1];
}
};
class Solution
{
public:
int stoneGameII(vector<int>& plies)
{
int len=piles.size();
vector<vector<int> > dp(len,veector<int>(len,0));
vector<int> sum(len,0);
//逆序部分和
sum.back()=piles.back();
for(int i=len-2;i>=0;--i)
sum[i]=sum[i+1]+piles[i];
//倒着查找,dp[i][j]表示当前在i位置,且此时m=j+1时可以获得的最大收益
for(int i=len-1;i>=0;--i)
for(int j=0;j<len;++j)
{
//剩下的点可以一次拿完
int M=j+1;
if(2*M>=len-i)
dp[i][j]=sum[i];
else
{
//一次拿不完的情况,取最大值
for(int k=1;k<=2*M;++k)
dp[i][j]=max(dp[i][j],sum[i]-dp[i+k][max(k,M)-1]);
}
}
return dp[0][0];
}
};