1. 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:
示例 1:
输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
A:
这种初级题目就很简单了,将目标节点的val和next指向next的next就行
void deleteNode(ListNode* node) { ListNode* next_node = node->next; node->val = next_node->val; node->next = next_node->next; }
2. 删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
A:
方法1:遍历一次链表后,将所有的node存在一个list中,再删除list中指定的映射到原链表的node,可是这样会比较费时和费空间
ListNode* removeNthFromEnd(ListNode* head, int n) { vector<ListNode*> vec; ListNode* next = head->next; while (next) { vec.push_back(next); next = next->next; } next = vec[vec.size() - n]; next->val = next->next->val; next->next = next->next->next; return head; }
方法2:更快的办法应该使用快慢指针,即两个指针每次的步长一个大一个小
在本题中,先让快指针先走N步,再让慢指针和快指针一起走
ListNode* removeNthFromEnd(ListNode* head, int n) { if (head == NULL) return NULL; ListNode* fast = head;//快指针 ListNode* slow = head;//慢指针 //快指针提前移动n次 for (int i = 0; i < n; i++) { fast = fast->next; } //删除的是链表头部 if (fast == NULL) { return head->next; } //同时移动快慢指针,直到快指针到链表末尾 //说明慢指针在要删除的位置上 while (fast->next != NULL) { fast = fast->next; slow = slow->next; } slow->next = slow->next->next; return head; }
3. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
A:
就单纯个的反转链表
两种方法的效率都不错
ListNode* reverseList(ListNode* head) { if (head == NULL || head->next == NULL){ return head; } else { ListNode* newNode = reverseList(head->next); head->next->next = head; head->next = NULL; return newNode; } }
ListNode* reverseList(ListNode* head) { ListNode* ret = NULL; while (head) { ListNode* tmp = head->next; head->next = ret; ret = head; head = tmp; } return ret; }
4. 合并两个有序链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
A:
也就是单纯的合并链表了
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { struct ListNode* head = new ListNode(1); struct ListNode* now = head; while (l1 != NULL && l2 != NULL) { if (l1->val <= l2->val) { now->next = l1; l1 = l1->next; } else { now->next = l2; l2 = l2->next; } now = now->next; } if (l1 != NULL) { now->next = l1; } if (l2 != NULL) { now->next = l2; } return head->next; }
5 回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2 输出: false
示例 2:
输入: 1->2->2->1 输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
A:
利用快慢指针,找到整个链表的中点,然后反转后半段,再用前半段和后半段对比
bool isPalindrome(ListNode* head) { if (head == NULL || head->next == NULL) return true; /* stack<int> first_half;*/ ListNode* one = head; ListNode* two = head; /* first_half.push(one->val);*/ while (one->next != NULL && two->next != NULL && two->next->next != NULL) { one = one->next; two = two->next->next; /* first_half.push(one->val);*/ } if (two->next != NULL) { one = one->next; } ListNode* ref = NULL; ListNode* helf = one; while (one != NULL) { ListNode* tmp = one->next; one->next = ref; ref = one; one = tmp; } ListNode* p = head; while (ref != NULL) { if (ref->val != p->val) { return false; } ref = ref->next; p = p->next; } return true; }
方法2,利用栈先进后出的原理,再找前半段的同时将val push到stack中,再在遍历后半部分的时候将链表和stack对比
bool isPalindrome(ListNode* head) { if (head == NULL || head->next == NULL) return true; stack<int> first_half; ListNode* one = head; ListNode* two = head; first_half.push(one->val); while (one->next != NULL && two->next != NULL && two->next->next != NULL) { one = one->next; two = two->next->next; first_half.push(one->val); }
// if (two->next != NULL) { one = one->next; } while (one != NULL) { if (one->val != first_half.top()) { return false; } first_half.pop(); one = one->next; } return true; }
6 环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
A:
题目有点拗口,总是就是判断node是不是有环
同样是利用快慢指针,步长位1和2,只要是个环,快慢指针肯定会某一处相等
bool hasCycle(ListNode *head) { ListNode* one = head; ListNode* two = head; while (two != NULL && two->next != NULL) { one = one->next; two = two->next->next; if (one == two){ return true; } } return false; }