前天发了人生第一篇博客,没想到收到了点赞,感觉好开心,能被认可。我算法属实是一个小白,现在入门,意外发现这里很方便记笔记,就将自己的学习笔记放了上来,方便随时随地复习。现在发现还可以督促我学习哈哈哈,希望大家多多指教啦~,有什么好的学习方法大佬们若愿指点一二,hong感激不尽!算法真的感觉难,链表一道题我都要想好久,做不出再看讲解,然后自己再理解,虽道阻且长,但还是勇往直前吧!
注:这里收录的是我做不出、做错之类的我自己需要回顾的题目。
习题一:84. 求1+2+…+n
题解:我做题使用了递归,也是过了的,但是看了讲解后,发现递归的出口也是用到了判断,所以不符合题目要求,这里是正确解法。
class Solution {
public:
int getSum(int n) {
int res = n;
n > 0 && (res+=getSum(n-1));
return res;
}
};
其实还是递归,但是写法看起来相差挺大的。主要利用了&&的特性,如果左半边不成立则右半边就不会运行,直接停止了。
在上面还看到了一个看起来好牛逼的做法,y总都说第一次见!!!代码见下:
class Solution {
public:
int getSum(int n) {
char a[n][n+1];
return sizeof(a)>>1;
}
};
习题二:28. 在O(1)时间删除链表结点
代码如下:(注:我们只需在void deleteNode(ListNode* node){}的{}里面填写代码即可,其余的都已经给出。)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val=node->next->val;
node->next=node->next->next;
}
};
一开始我以为传入的是整个链表(我的惯性思维吧),所以我一开始的想法是找到该数值的结点的前一个结点,然后它指向需要删除的结点的下一个结点。 其实传入的是要删除的结点的地址,所以正确的做法是可以“耍点小心机”,嘿嘿,将原本要删除的结点node的val值改为它指向的结点的val,再将node的next指向它指向的结点所指向的结点,这样就伪装成功,是不是有点绕?来个图解:
习题三:78. 左旋转字符串
题解:substr()函数的使用
class Solution {
public:
string leftRotateString(string str, int n) {
return str.substr(n)+str.substr(0,n);//substr(起始位置,字符总个数)
//如果从起始位置开始一直到整个字符串结束,则字符总个数可以省略。
}
};
习题四:87. 把字符串转换成整数(难,┭┮﹏┭┮)
本题限制了使用函数,但是有两个函数是可以将字符串变成整数的,以字符串str为例:
①atoi(str.c_str()) ②stoi(str) 两个函数的返回值类型都是int
题解:(步骤和解析在代码注释里了)
class Solution {
public:
int strToInt(string str) {
int k=0;
//先过掉空格
for(char c:str)
{
if(c==' ')
k++;
}
//再处理±问题
int num=1;
if(str[k]=='-')
{
num=-1;
k++;
}
else if(str[k]=='+') k++;
//开始处理数字,用每循环*10进行
long long res=0;//数值会很大,要注意用long long
while(k<str.size()&&str[k]>='0'&&str[k]<='9')
{
res=res*10+str[k]-'0';//str[k]-'0'这里就是将字符串变成0-9的整数
k++;
//因为存入的是绝对值。所以就无法直接与 INT_MAX和INT_MIN进行判断
//所以这里的想法就是,通过计算机得到2的31次方是10位数,所以只要判断res>10的11次方就一定不在范围里
if(res>1e11) break;
}
//这时再加上±,与 INT_MAX和INT_MIN进行判断
res=res*num;
if(res>=INT_MAX) res=INT_MAX;
if(res<=INT_MIN) res=INT_MIN;
return res;
}
};
习题五:35. 反转链表
题解:因为找不到前一个结点,所以设两个新指针p,q,再设指针o保存q的下一个结点,将q的next指向p,然后p=q,q=o。这样进行循环,直到q为空。注意:别忘了将head的next指向空!!!
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head||head->next==NULL) return head;
ListNode *p,*q;
p=head;
q=p->next;
while(q)
{
auto o=q->next;
q->next=p;
p=q;
q=o;
}
head->next=NULL;
return p;
}
};
习题六:66. 两个链表的第一个公共结点
我的思路是将两个链表都反过来,然后找到它们最后一个相同的结点,这个结点就是它们原来共同的第一个结点,但是时间超了。。。
题解:(太巧妙了!o(╥﹏╥)o)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
ListNode *p = headA, *q = headB;
while(p!=q)
{
if(p) p=p->next;//p不为空,就往下一个结点走
else p=headB;//为空就到另一条链表
if(q) q=q->next;//与p类似
else q=headA;
}
return p;
}
};
习题七:29. 删除链表中重复的节点
题解:
原理:让q往后找是否有和自己相同的结点,直到下一个结点不一样,这时p->next=q->next.
哨兵指针:当第一个结点可能被删时,要加一个哨兵,到时候传它的下一个结点。例1为例:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* head) {
auto dummy=new ListNode(-1);//哨兵
dummy->next=head;
auto p=dummy;
while(p->next)
{
auto q=p->next;
while(q->next)//找q后一个结点与它不相同
{
if(q->val==q->next->val) q=q->next;
else break;
}
if(p->next==q) p=q,q=q->next;
else p->next=q->next;
}
return dummy->next;
}
};