复习了一下链表。下面做了一些简单题。
237. 删除链表中的元素
题目:
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:
4 -> 5 -> 1 -> 9
示例 1:
输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1 输出: [4,5,9] 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
- 链表至少包含两个节点。
- 链表中所有节点的值都是唯一的。
- 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
- 不要从你的函数中返回任何结果。
思路:
这道题很巧妙,函数只给了一个结点。题目要求是删除该结点。那么我们只需要将上个结点的后继指向下一个结点。然而上一结点的信息我们并不知道。所以,我们只能将这一结点替代下一结点,下一结点没有结点指向。
程序:
/**
* 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) {
ListNode *p = node->next;
node->val = p->val;
node->next = p->next;
}
};
203. 移除链表元素
题目:
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5
思路:
由于这是一个单链表,删除节点需要上一非目标节点指向该节点后续的非目标节点,因此,需要两个指针,指针一是只指向非目标节点的,而指针二是用来判断节点的。
程序:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *res = new ListNode(-1);
ListNode *p = res;
ListNode *q = head;
while (q != NULL){
if (q->val != val){
p->next = q;
p = p->next;
}
q = q->next;
}
p->next = NULL;
return res->next;
}
};
83. 删除排序链表中的重复元素
题目:
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2 输出: 1->2
示例 2:
输入: 1->1->2->3->3 输出: 1->2->3
思路:
这题思路比较简单,有序、不重复,直接判断当前值和下一值即可。
程序:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode *p = head;
if (head == nullptr){
return head;
}
while (p->next){
if (p->val == p->next->val){
p->next = p->next->next;
}
else{
p = p->next;
}
}
return head;
}
};
876. 链表的中间结点
题目:
给定一个带有头结点 head
的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。 注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6] 输出:此列表中的结点 4 (序列化形式:[4,5,6]) 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
提示:
- 给定链表的结点数介于
1
和100
之间。
思路:
这道题求中点,很容易想到快慢指针,速度快一倍,当快指针指向NULL时,慢指针正好指向中点。
程序:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *fast,*slow;
fast = head;
slow = head;
while (fast != NULL && fast->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
141. 环形链表
题目:
给定一个链表,判断链表中是否有环。
进阶:
你能否不使用额外空间解决此题?
思路:
依题意,我们可知道,该环只能在链表末尾的,不可能在中间和首。那么,可以想象,当一个指针进入环后会无限循环下去。我们只需再放一个指针从头进入,且速度比第一个指针慢即可。它们最终会在环内相遇。若没环,则指针会指向NULL。
程序:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast,*slow;
fast = head;
slow = head;
while (fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if (fast == slow){
return true;
}
}
return false;
/* if (!head || !head->next) // 判断是循环链表,理解错误
return false;
ListNode *p = head;
while (p->next){
if (p->next == head)
return true;
p = p->next;
}
return false;
*/
}
};
160. 相交链表
题目:
编写一个程序,找到两个单链表相交的起始节点。
例如,下面的两个链表:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
在节点 c1 开始相交。
注意:
- 如果两个链表没有交点,返回
null
. - 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路:
这题有两个思路:
1. 得到两个链表的长度,然后删去长链表的头,使得两个链表相等。随后从头开始比对。
2. 若两链表长度不相等,则正常比对到NULL也不会得到相等的。然而,两个长度不一的链表各自加上对方,则会得到两个相等长度的链表。由此,我们可以 第一次遇到NULL的时候,转向另一条链表的头,若相交,必会在交点相遇。
程序:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p,*q;
p = headA;
q = headB;
while (p != q){
if (p == NULL){
p = headB;
}
else{
p = p->next;
}
if (q == NULL){
q = headA;
}
else{
q = q->next;
}
}
return p;
/* int i = 0,j = 0;
ListNode *p = headA,*q = headB;
if (p == NULL || q == NULL)
return NULL;
while (p != NULL){
p = p->next;
i++;
}
while (q != NULL){
q = q->next;
j++;
}
int dis = i - j;
p = headA;
q = headB;
if (dis >= 0){
while (dis != 0 && p != NULL){
p = p->next;
dis--;
}
}
else{
while (dis != 0 && q != NULL){
q = q->next;
dis++;
}
}
while (p != NULL){
if (p == q){
return p;
}
p = p->next;
q = q->next;
}
return NULL;*/
}
};
21. 合并两个有序链表
题目:
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
思路:
1. 直接创建一个新链表,比对两条链表,小的往里面放即可。
2. 递归
程序:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *head = new ListNode(-1);
ListNode *p = head;
if (l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
while (l1 != NULL && l2 != NULL){
if (l1->val < l2->val){
p->next = l1;
p = p->next;
l1 = l1->next;
}
else{
p->next = l2;
p = p->next;
l2 = l2->next;
}
}
if (l1 == NULL && l2 != NULL){
p->next = l2;
}
if (l2 == NULL && l1 != NULL){
p->next = l1;
}
return head->next;
/* if (l1 == NULL) // 递归
return l2;
if (l2 == NULL)
return l1;
if (l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}
else{
l2->next = mergeTwoLists(l2->next,l1);
return l2;
}*/
}
};
206. 反转链表
题目:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
思路:
该题思路比较死板的方法就是建个数组(栈),先入再出。另一种就是用两个指针,循环往回指即可。
程序:
/**
* 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 *ans = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return ans;
/* if (!head || !head->next)
return head;
ListNode *p = head;
ListNode *tmp,*q;
q = p->next;
p->next = NULL;
while (q){
tmp = q->next;
q->next = p;
p = q;
q = tmp;
}
return p;*/
}
};