您的位置:首页 > 其它

【LeetCode61-70】旋转链表,三道标准DP问题,正则表达式,word文字排版规则,

2017-04-02 13:33 381 查看



61.在K位置旋转链表

Given 
1->2->3->4->5->NULL
 and 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;
}

祝清明节快乐呀~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息