【LeetCode61-70】旋转链表,三道标准DP问题,正则表达式,word文字排版规则,
2017-04-02 13:33
381 查看
61.在K位置旋转链表
Given 1->2->3->4->5->NULLand k =
2,
//往后挪两位
return
4->5->1->2->3->NULL.
//好久没用指针都有些疏忽了
新建一个ListNode *temp直接等于指针就意味着把那个位置储存住了,例如:
ListNode *front = head;//保存头部位置
ListNode **temp=&head的意思是指向指针的地址,随着指针的变化一起变化…………
class Solution { public: ListNode* rotateRight(ListNode* head, int k) { if(k==0||!head)return head;//解决k=0或者head为空的情况 ListNode *front = head;//保存头部位置 ListNode result(0); ListNode *temp = &result; int i = 1; while (head->next!=NULL) { ++i; head = head->next; } ListNode *tail = head->next;//尾巴的空指针 head->next = front;//形成了一个环 k=k%i;if(k==0)k=i; for (int j = 0; j < i - k ; ++j)head = head->next; temp->next = head->next;//把链表开始的地方储存到result head->next = tail;//断开环接到之前的尾巴上 return result.next; } };
62.类似于象棋里的兵卒移动问题(标准的DP问题)
计算出有多少种路径,机器人只能向右或向下Above is a 3 x 7 grid. How many possible unique paths are there?
Note: m and n will be at most 100.
最直观的思路就是迭代了,代码就两三行,逻辑上肯定没问题
class Solution { public: int uniquePaths(int m, int n) { if(m==1||n==1)return 1; return uniquePaths(m-1,n)+uniquePaths(m,n-1); } };
然而果不其然在m=19,n=13的时候超过限制了,不断用迭代确实很费时间
仔细分析了下,例如计算f(50,50)必须把f(49,50)以及f(50,49)从头到尾都计算一遍,这完全没必要,只要浪费空间储存一下即可,所以下面这个就完全满足条件了
本质上就是DP规划
class Solution { public: int uniquePaths(int m, int n) { vector<vector<int>>result(m, vector<int>(n,1)); for (int i = 1; i < m; ++i) { for (int j = 1; j < n; ++j) result[i][j] = result[i - 1][j] + result[i][j - 1]; } return result[m - 1][n - 1]; // if (m == 1 || n == 1)return 1; // return uniquePaths(m - 1, n) + uniquePaths(m, n - 1); } };后来仔细想想,根本无需n*m的空间,一行就足够了……
class Solution { int uniquePaths(int m, int n) { if (m > n) return uniquePaths(n, m); vector<int> cur(m, 1); for (int j = 1; j < n; j++) for (int i = 1; i < m; i++) cur[i] += cur[i - 1]; return cur[m - 1]; } };
63.特殊路径2(在上一题上加了障碍)
//直接在原来数据上进行DP……只击败了4%的人……class Solution { public: int uniquePathsWithObstacles(vector<vector<int>>& field) {//obstacleGrid if(field[0][0]==1)return 0; field[0][0]=1; int m=field.size(),n=field[0].size(); int temp=1; for(int i=1;i<n;++i){ if(field[0][i]==1)temp=0; field[0][i]=temp; } temp=1; for(int j=1;j<m;++j){ if(field[j][0]==1)temp=0; field[j][0]=temp; } for(int i=1;i<m;++i){ for(int j=1;j<n;++j){ if(field[i][j]==0)field[i][j]=field[i-1][j]+field[i][j-1]; else field[i][j]=0; } } return field[m-1][n-1]; } };
继而看了Top Solution里的一个解法,通过新建一个大了一围的vector简洁了好多…………
在上面以及左边加了一行,并且初始化为0,只把最上面的第二个初始化为1……接着不断填满整个……看着代码就觉得舒畅…
class Solution { public: int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) { int m = obstacleGrid.size(), n = obstacleGrid[0].size(); vector<vector<int> > dp(m + 1, vector<int> (n + 1, 0)); dp[0][1] = 1; for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) if (!obstacleGrid[i - 1][j - 1]) dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; return dp[m] ; } };
64.最小路径
找到一条从左上到右下角的路径使得和最小又是一道DP问题
class Solution { public: int minPathSum(vector<vector<int>>& grid) { //直观上觉得是个DP问题 if(grid.size()==0)return 0; int m=grid.size(),n=grid[0].size(); for(int i=1;i<n;++i)grid[0][i]+=grid[0][i-1]; for(int j=1;j<m;++j)grid[j][0]+=grid[j-1][0]; for(int i=1;i<m;++i){ for(int j=1;j<n;++j)grid[i][j]+=std::min(grid[i-1][j],grid[i][j-1]); } return grid[m-1][n-1]; } };
65.判断字符串是否是有效数字
Some examples:"0"=>
true
" 0.1 "=>
true
"abc"=>
false
"1 a"=>
false
"2e10"=>
true
//感谢机油的帮助,正则表达式真的好方便……
regex test{ "^\\s*[-|+]?((\\.[0-9]+)|([0-9]+\\.?[0-9]*))(e[-|+]?[0-9]+|)\\s*$" }; class Solution { public: bool isNumber(string s) { return regex_match(s, test); } };
66.数字加一(vector<int>存储数字)
实现数字+1,这个很长的数字用vector<int>存储,高位在前面//注意vector的insert用法
digits.insert(digits.begin(),1);
我的解法:只击败了2%
class Solution { public: vector<int> plusOne(vector<int>& digits) { int add=1,n=digits.size()-1; while(add){ help(digits,n,add); n--; } return digits; } void help(vector<int>& digits,int location,int &add){ if(location==-1){digits.insert(digits.begin(),1);add=0;return;}//注意insert用法! if((digits[location]+=add)==10)digits[location]-=10; else add=0; return; } };
下面是别人的优雅很多的解法://很正常的20%了…
class Solution { public: vector<int> plusOne(vector<int> &digits) { //从后往前,碰到9就变成0,否则+1返回 for(int i = digits.size() - 1; i >= 0; -- i) { if(digits[i]==9) digits[i] = 0; else { ++ digits[i]; return digits; } } // 最高位改成1,最后再添加个0 digits[0] = 1; digits.push_back(0); return digits; } };
67.两个二进制数相加(string格式)
//reverse了一下再加的……方便一些class Solution { public: string addBinary(string a, string b) { int n=max(a.size(),b.size())+1; int add=0; reverse(a.begin(),a.end()); reverse(b.begin(),b.end()); string result=""; for(int i=0;i<n;++i){ int temp=0; if(i<a.size())temp+=(a[i]-'0'); if(i<b.size())temp+=(b[i]-'0'); temp+=add; if(i!=n-1||add) result+=to_string(temp%2); add=temp/2; } reverse(result.begin(),result.end()); return result; } };
然后看到一段别人的非常精简漂亮的代码
class Solution { public: string addBinary(string a, string b) { string s = ""; int c = 0, i = a.size() - 1, j = b.size() - 1; while(i >= 0 || j >= 0 || c == 1) { c += i >= 0 ? a[i --] - '0' : 0; c += j >= 0 ? b[j --] - '0' : 0; s = char(c % 2 + '0') + s; c /= 2; } return s; } };
68.文字排版
空格初始化string的方法:string(n,' ');注意是单引号…………
限定每行maxWidth个字符,遵循靠左原则。如果一行只有一个用空格填满,否则单词靠最右,单词之间用空格填充,左侧优先级高于右边……
//简而言之就一句话:使用word的规则……
//注意变量的有效范围…刚刚调这个bug调了半天,囧
class Solution {
public:
vector<string> fullJustify(vector<string>& words, int maxWidth) {
vector<string>result;
int begin = 0;
for (int i = 0; i<words.size();) {
int length = 0;
string temp = "";
while (length <= maxWidth&&i<words.size()) {
length += (i == begin) ? words[i].size() : words[i].size() + 1;
if (length > maxWidth) { help(temp, words, begin, i - 1, maxWidth); begin = i; break; }
else if (i<words.size()) { temp += (i == begin) ? words[i] : (" " + words[i]); ++i; }
}
if (i == words.size())help(temp, words, words.size() - 1, words.size() - 1, maxWidth);
result.push_back(temp);
}
//
return result;
}
void help(string &temp, vector<string>&words, int begin, int end, int maxWidth) {
int size = end - begin;
int length = maxWidth - temp.size();
if (size == 0) { for (int i = 0; i < length; ++i)temp += " "; return; }
vector<string>ZZ(size, " ");
int i = 0;
while (length > 0) {
i %= size;
ZZ[i] += " ";
i++;
length--;
}
temp = words[begin];
for (int i = 0; i < size; ++i) {
temp += ZZ[i];
temp += words[begin + i + 1];
}
return;
}
};
别人的看着很简洁的方法:
vector<string> res;
for (int i = 0, k, l; i < words.size(); i += k) {
for (k = l = 0; i + k < words.size() & l + words[i + k].size() <= L - k; k++) {
l+= words[i + k].size();
}
string tmp = words[i];
for (int j = 0; j < k - 1; j++) {
if (i + k >= words.size()) tmp += " ";
else tmp += string((L - l) / (k - 1) + (j < (L - l) % (k - 1)), ' ');
tmp += words[i + j + 1];
}
tmp += string(L - tmp.size(), ' ');
res.push_back(tmp);
}
return res;
}
69.求平方根
方法一:直接用sqrt只击败了7%…class Solution {
public:
int mySqrt(int x) {
return sqrt(x);
}
};方法二:然后自己写了个,只击败了6%,想着移位运算符快一点儿再++,然而并没有很快…
class Solution {
public:
int mySqrt(int x) {
int result = x;
result=result >> 1;//>>是除以2,记得要写result=...日了狗
while (long(result)*long(result) > x)result = result >> 1;
while (long(result)*long(result) <= x)result++;
return result-1;
}
};
方法三:参考了一种方法击败了8%,挺巧妙的(把参数0.00001修改成0.1立马跻身70%了……)确实很巧妙啊!!!
For instance, when calculate sqrt(2) :
Guess Result Quotient Average Result 1 2 / 1 = 2 (2 + 1) / 2 = 1.5 1.5 2 / 1.5 = 1.3333 (1.3333 + 1.5) / 2 = 1.4167 1.4167 2 / 1.4167 = 1.4118 (1.4167 + 1.4118) / 2 = 1.4142 ... ...
int mySqrt(int x) {
double ans = x;
double delta = 0.0001;
while (fabs(pow(ans, 2) - x) > delta) {
ans = (ans + x / ans) / 2;
}
return ans;
}
方法四:(一样7%)时间复杂度O(log n)
class Solution {
public:
int mySqrt(int x) {
if(x==0)
return 0;
int h=0;
while((long)(1<<h)*(long)(1<<h)<=x) // firstly, find the most significant bit
h++;
h--;
int b=h-1;
int res=(1<<h);
while(b>=0){ // find the remaining bits
if((long)(res | (1<<b))*(long)(res |(1<<b))<=x)
res|=(1<<b);
b--;
}
return res;
}
};
70.爬楼梯(斐波拉契数列)
每次只能爬1-2步,爬n步总共有多少种路径?0ms的解法:
//迭代固然很明了,但太耗费时间了,完全可以记录下来!
class Solution {
public:
int climbStairs(int n) {
int result=0;
if(n==1)return 1;
if(n==2)return 2;
int a=1,b=2;
// return climbStairs(n-1)+climbStairs(n-2);//这种太耗费时间了,得存储下来
for(int i=0;i<n-2;i++){
a+=b;
swap(a,b);
}
return b;
}
};
另外一种思路一样,但简洁一些的代码:
好优美啊!!
int climbStairs(int n) {
int a = 1, b = 1;
while (n--)
a = (b += a) - a;
return a;
}
祝清明节快乐呀~
相关文章推荐
- 解析php利用正则表达式解决采集内容排版的问题
- 链表系列-把链表向右旋转k个位置LeetCode#61. Rotate List
- leetCode 61.Rotate List (旋转链表) 解题思路和方法
- LeetCode-----61. Rotate List(循环旋转链表)
- 【dp】正则表达式匹配问题
- leetCode 61.Rotate List (旋转链表) 解题思路和方法
- Leetcode 61. Rotate List (旋转链表)
- leetcode之链表逆序翻转类-----92/206 逆序 24/25/61/143 按规则翻转 86/234 双指针分治 19/82/83/203 按规则删除
- 解析php利用正则表达式解决采集内容排版的问题
- 【LeetCode题解】61_旋转链表(Rotate-List)
- leetcode 61. Rotate List 向右旋转k个元素 + 链表环遍历
- leetcode解题61. Rotate List java版(旋转链表)
- php利用正则表达式解决采集内容排版问题
- LeetCode 61. Rotate List(旋转链表)
- 巧用正则表达式将Word文字替换为图片
- [LeetCode] 61. Rotate List 旋转链表
- 巧夺天工:采用正则表达式解决树匹配问题
- 正则表达式教程-正则表达式匹配规则(6)
- 正则表达式去掉word转为html后的垃圾样式
- 转:关于脏字典过滤问题-用正则表达式来过滤脏数据