这几天真是忙的不可开交,主要是因为要学的东西太多了,本人又有完美主主义倾向,所以对于一些知识就非常浪费时间,这样做有点好处就是理解深刻,但缺点就是太费时间。话说回来,算法这种东西,是有必要深追究的,因为这是往大了说是一个创造的工作,往小了说最起码也是匹配吧。你最少得知道什么情况该用什么算法吧,如果你只是把一个算法翻译成代码(当然这也不是一个简单的工作),那你学的算法是完全没有用武之地的,甚至那根本就不叫你学的算法,你只是一个编码者罢了。
当然学习这种事不可能是一帆风顺的,你学的越多越感觉自己渺小。尤其是当你根本不理解别人那三五行的代码时。其实这就是算法的魅力,还是调整心态,放低自己,切记不要骄傲自满,觉得自己会几个简单的算法就厉害了。总有比你高得多的高人告诉你:程序,不是这么写得~
好了,废话不多说了,赶紧上题吧。
Given a linked list, swap every two adjacent nodes and return its head.
For example,
Given 1->2->3->4
, you should return the list as 2->1->4->3
.
Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.
这是leetcode第24题,理解上面难度不是很大,就是给你一个链表,将里面的节点两两互换了,注意是节点交换,不能改变节点的值,说白了,就是要考察你对节点指针的运用。
怎么说呢,这其实是一个数据结构的方法实现问题。也算是一个算法吧,一个应用背景很明确的算法。主要就看你会不会被各个指针弄糊涂了。
边界条件!
指针判空!
没有头结点!
这些东西已经是重复了n遍了,别的地方可以错(当然最后别错),这些地方绝对不能再错了,否则真是无可救药了!
直接上代码吧
//Definition for singly-linked list.
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
//指针即边界条件判断
if(head==NULL || head->next==NULL)
return head;
//指针定义
ListNode* pFirst=head;
ListNode* pSecond=head->next;
ListNode* pThrid = NULL;
ListNode* pForth = NULL;
head=pSecond;//改变头指针
while(1)
{
if(pFirst&&pSecond)
{
pThrid = pSecond->next;
pSecond->next = pFirst;
if(pThrid!=NULL && pThrid->next!=NULL)
{
pForth=pThrid->next;
pFirst->next = pForth;
}
else
{
pFirst->next = pThrid;
break;
}
}
pFirst=pThrid;
pSecond=pForth;
}
return head;
}
};
显然时间复杂度为O(n)。至于逻辑,自己一定要画个链表走一遍,这样才能明白,别人说再多没啥用。
我在开始编码时犯了一个错误,就是忘了pFirst正常情况下(即后面还有足够多元素)是应该指向pForth的,而指向了pThrid。其实也不是忘了,就是没想到这一层,所以说这种题写完代码之后如果时间允许是一定要举几个具体例子自己捋一遍的。不要把题看小了,把自己看大了。说实在的,你没有太多机会犯错误的,如果你有三次面试机会,每个面试问三道题,那就相当于你只有一次机会来做对一道题换取这份工作。错一次就什么都没有了,所以不要把调试程序当成你程序设计不可缺少的一部分,进入调试证明你已经失业!
这次写的算法不多,“没用”的说了不少,因为确实就是个细心的问题,或者说,是一个态度问题。这段时间很忙,也很茫,希望自己可以调整好。多学点儿有用的知识。