LeetCode—61(旋转链表)
方法:此题一种方法,是利用快慢指针,快指针先走k步,然后两个指针一起走,当快指针走到末尾时,满指针指的下一个位置即是新顺序的头结点(特殊情况链表为空,k>n)。另一种方法,一个指针即可,就是先遍历整个链表获得链表长度n,然后链表的头和尾接起来,然后往后走 n - (k % n),就到达了新链表的头节点前一个点,这是断开链表即可。
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(!head) return NULL;
int n =1;
ListNode *cur = head;
while(cur -> next){
++n;
cur = cur -> next;
}
cur -> next = head;
int m = n - k%n;
for(int i = 0;i < m;i++){
cur = cur -> next;
}
//断开链表
ListNode *newhead = cur -> next;
cur -> next = NULL;
return newhead;
}
};
LeetCode—62(不同路径)
方法:第一反应是递归的题目(DFS)因为是求全部合理的路径,但是这样做会超时。这道题利用动态规划,DP方法,由于每个格子的路径选择,只与它相邻的上面与左面有关联,则可得下图。
C++代码:
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> dp(n,1);
for(int i = 1;i < m;i++){
for(int j = 1;j < n;j++){
dp[j] += dp[j-1];//看图容易明白,一层一层更新
}
}
return dp[n-1];//dp从零开始
}
};
LeetCode—63(不同路径II)
方法:跟上一道题,类似,一样的方法,需要注意的是,当遇到障碍,将其赋值0.尤其要考虑特殊的情况。
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if (obstacleGrid.empty() || obstacleGrid[0].empty() || obstacleGrid[0][0] == 1) return 0;//特殊情况需考虑
vector<long long> dp(obstacleGrid[0].size(),0);//记得long类型,不然路径数量会大于INT_MAX
dp[0] = 1;
for(int i = 0;i < obstacleGrid.size();i++){
for(int j = 0;j < obstacleGrid[0].size();j++){
if(obstacleGrid[i][j] == 1) {dp[j] = 0;}
else if(j>0){
dp[j] += dp[j-1];
}
}
}
return dp[obstacleGrid[0].size()-1];
}
};
LeetCode—64(最小路径和)
C++代码:跟上一题的思路类似,利用上一格的值与左一格的值作比较,取最小,然后加上现在的值,没写出来是因为不知道边缘怎么处理,直接单独写个循环就可以。在考虑其他的。
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size(),n = grid[0].size();
int dp[m][n];
dp[0][0] = grid[0][0];
//先进行边缘的值相加,利用两个循环
for(int i = 1;i < m;i++) dp[i][0] = grid[i][0] + dp[i-1][0];
for(int j = 1;j < n;j++) dp[0][j] = grid[0][j] + dp[0][j-1];
for(int i = 1;i < m;i++){
for(int j = 1;j < n;j++){
dp[i][j] = grid[i][j] + min(dp[i][j-1],dp[i-1][j]);
}
}
return dp[m-1][n-1];
}
};
LeetCode—65(有效数字)
方法:我们从题目中给的一些例子可以分析出来,我们所需要关注的除了数字以外的特殊字符有空格’ ‘,小数点’.’,自然数’e/E’,
还要加上正负号’+/-’,除了这些字符需要考虑意外,出现了任何其他的字符,可以马上判定不是数字。下面逐一分析情况:
1.空格’ ‘:两种情况,出现在开头或结尾,另一种出现在中间的字符。出现在开头和末尾的空格不影响数字,而一旦中间出现了空格,则判定不是数字。
2.小数点’.’:小数点分的情况较多,首先的是小数点只能出现一次,但是小数点可以出现在任何位置,但是不能出现在自然数e/E之后,例如’1e.1’false,’1e1.1‘false。还有小数点位于末尾时,前面必须是数字,’-.‘false。三个位置分情况讨论。
3.自然数’e/E’:自然数的前后必须有数字,即自然数不能出现在开头或结尾,如 “e” false, “.e1” false, “3.e” false, “3.e1” true。
4.符号’+/-’:符号前面如果有字符的话必须是空格或者自然底数。
C++代码:
class Solution {
public:
bool isNumber(string s) {
//num, dot, exp, sign分别表示数字,小数点,自然底数和符号是否出现
//numAfterE表示自然底数后面是否有数字
bool num = false, numAfterE = true, dot = false, exp = false, sign = false;
int n = s.size();
for (int i = 0; i < n; ++i) {
if (s[i] == ' ') {
if (i < n - 1 && s[i + 1] != ' ' && (num || dot || exp || sign)) return false;
} else if (s[i] == '+' || s[i] == '-') {
if (i > 0 && s[i - 1] != 'e' && s[i - 1] != ' ') return false;
sign = true;
} else if (s[i] >= '0' && s[i] <= '9') {
num = true;
numAfterE = true;
} else if (s[i] == '.') {
if (dot || exp) return false;
dot = true;
} else if (s[i] == 'e') {
if (exp || !num) return false;
exp = true;
numAfterE = false;
} else return false;
}
return num && numAfterE;
}
};