OJ连接:https://leetcode-cn.com/problems/reverse-linked-list/description/html
// 三个指针翻转的思路 /** * 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 == NULL || head->next == NULL) return head; ListNode* n1, *n2, *n3; n1 = NULL; n2 = head; n3 = n2->next; //中间节点不为空,继续修改指向 while(n2) { //中间节点指向反转 n2->next = n1; //更新三个连续的节点 n1 = n2; n2 = n3; // 须要注意到最后两个节点时,n3已经为空 if(n3) n3 = n3->next; } //返回新的头 return n1; } }; // 头插的思路 /** * 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) { ListNode* newhead = NULL; ListNode* cur = head; while(cur) { struct ListNode* next = cur->next; //头插新节点,更新头 cur->next = newhead; newhead = cur; cur = next; } return newhead; } };
须要注意本题要求了复杂度为O(N),空间复杂度为O(1)web
一、本题说明了链表的长度小于900,因此这里咱们能够开辟一个900个空间的数组,将链表的数据放到数组中再进行判断。这种方法虽然能过OJ,可是实际面试中是不符合面试官的要求的。面试
二、经过slow走一步,fast走两步,找到中间节点。而后将后半段链表反转,反转后的链表跟原链表对比是否相同,相同则是回文结构。这样写才知足上面的对复杂度的要求。数组
/* 此题也能够先把链表中的元素值所有保存到数组中,而后再判断数组是否为回文。不建议使用这种解法,由于若是没有告诉链表最大长度,则不能同此解法 */ class PalindromeList { public: bool chkPalindrome(ListNode* A) { // write code here int a[900] = {0}; ListNode* cur = A; int n = 0; //保存链表元素 while(cur) { a[n++] = cur->val; cur = cur->next; } //判断数组是否为回文结构 int begin = 0, end = n-1; while(begin < end) { if(a[begin] != a[end]) return false; ++begin; --end; } return true; } }; /* 解题思路: 此题能够先找到中间节点,而后把后半部分逆置,最近先后两部分一一比对,若是节点的值所有相同,则即为回文。 */ class PalindromeList { public: bool chkPalindrome(ListNode* A) { if (A == NULL || A->next == NULL) return true; ListNode* slow, *fast, *prev, *cur, *nxt; slow = fast = A; //找到中间节点 while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } prev = NULL; //后半部分逆置 cur = slow; while (cur) { nxt = cur->next; cur->next = prev; prev = cur; cur = nxt; } //逐点比对 while (A && prev) { if (A->val != prev->val) return false; A = A->next; prev = prev->next; } return true; } };
OJ连接:https://www.nowcoder.com/practice/fc533c45b73a41b0b44ccba763f866ef?tpId=13&&tqId=11209&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking数据结构
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ /* 解题思路: 此题能够先找出相同节点的区间,而后删除区间中的全部值,直到把链表遍历完结束 */ class Solution { public: ListNode* deleteDuplication(ListNode* pHead) { if(pHead == NULL || pHead->next == NULL) return pHead; ListNode* n1 = NULL; ListNode* n2 = pHead; ListNode* n3 = n2->next; while(n3 != NULL) { //若是相邻节点不相同,则不须要删除,更新节点,继续向后遍历 if(n2->val != n3->val) { n1 = n2; n2 = n3; n3 = n3->next; } else { //若是相邻节点相同 //则n3去找第一个不相同的节点 while(n3 && n3->val == n2->val) { n3 = n3->next; } //从新连接,若是要删除的包括头节点,则更新头节点 if(n1) n1->next = n3; else pHead = n3; // 删除掉重复的节点 while(n2 != n3) { ListNode* next = n2->next; delete n2; n2 = next; } //更新节点 n2 = n3; if(n3) n3 = n3->next; } } return pHead; } };
OJ连接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/description/dom
此题能够分三步进行:ide
/* // Definition for a Node. class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; */ class Solution { public: Node* copyRandomList(Node* head) { // 1.拷贝链表,并插入到原节点的后面 Node* cur = head; while(cur) { Node* copy = new Node(cur->val); Node* next = cur->next; // 插入 cur->next = copy; copy->next = next; // 迭代往下走 cur = next; } // 2.置拷贝节点的random cur = head; while(cur) { Node* copy = cur->next; if(cur->random != NULL) copy->random = cur->random->next; else copy->random = NULL; cur = copy->next; } // 3.解拷贝节点,连接拷贝节点 Node* copyHead = NULL, *copyTail = NULL; cur = head; while(cur) { Node* copy = cur->next; Node* next = copy->next; // copy解下来尾插连接到拷贝节点 if(copyTail == NULL) { copyHead = copyTail = copy; } else { copyTail->next = copy; copyTail = copy; } cur->next = next; cur = next; } return copyHead; } };
/*思路跟上面的方法基本一致,差异再也不是拷贝节点挂在原节点后面创建映射关系,而是经过将原节点和拷贝节点存储到map中创建映射关系,这样也是经过3步就能够复制出拷贝链表*/ // 1.拷贝链表,使用map创建原链表节点和拷贝节点的映射 // 2.置拷贝节点的random. 经过map找到node->random的拷贝节点,就能够值copy节点的random。 // 3.从map中找到拷贝节点,连接拷贝节点 // Definition for a Node. class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; */ class Solution { public: Node* copyRandomList(Node* head) { map<Node*, Node*> nodeCopyMap; // 1.拷贝链表,使用map创建原链表节点和拷贝节点的映射 Node* cur = head; while(cur) { Node* copy = new Node(cur->val); nodeCopyMap[cur] = copy; cur = cur->next; } // 2.置拷贝节点的random cur = head; while(cur) { Node* copy = nodeCopyMap[cur]; if(cur->random != NULL) copy->random = nodeCopyMap[cur->random]; else copy->random = NULL; cur = cur->next; } // 3.从map中找到拷贝节点,连接拷贝节点 Node* copyHead = NULL, *copyTail = NULL; cur = head; while(cur) { // 找到cur映射的拷贝节点 Node* copy = nodeCopyMap[cur]; if(copyTail == NULL) { copyHead = copyTail = copy; } else { copyTail->next = copy; copyTail = copy; } cur = cur->next; } return copyHead; } };
若是你看了之后不是很明白,你能够点击看下面的视频讲解:
视频讲解(鼠标点这里)svg
数据结构常见链表面试题剖析(下)3d
更多学资料公开课请点击这里:联系我