在原链表的基础上直接删除指定元素
struct ListNode* removeElements(struct ListNode* head, int val) {
struct ListNode* cur = head;
struct ListNode* prev = head;
//判断头节点
while(head && head->val == val)
{
head = head->next;
}
//链表为空
if(head == NULL)
{
return NULL;
}
//正常情况
while(cur)
{
if(cur->val == val)
{
prev->next = cur->next;
}
else
{
prev = cur;
}
cur = cur->next;
}
return head;
}
创建一个新的链表存放未删除的元素
struct ListNode* removeElements(struct ListNode* head, int val) {
//设置新链表的头
struct ListNode* newhead = (struct ListNode*)malloc(sizeof(struct ListNode));
newhead->val = -1;
newhead->next = NULL;
struct ListNode* cur = head;
struct ListNode* tail = newhead;
while(cur)
{
if(cur->val == val)
{
cur = cur->next;
}
else
{
tail->next = cur;
tail = tail->next;
cur = cur->next;
}
}
//将新链表与原链表断开
tail->next = NULL;
struct ListNode* ret = newhead->next;
free(newhead);
newhead = tail = NULL;
return ret;
}
创建一个新的链表
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//定义新链表的头
struct ListNode* newhead = (struct ListNode*)malloc(sizeof(struct ListNode));
newhead->val = -1;
newhead->next = NULL;
struct ListNode* tail = newhead;
//比较链表元素
while(list1 && list2)
{
if(list1->val < list2->val)
{
tail->next = list1;
tail = tail->next;
list1 = list1->next;
}
else
{
tail->next = list2;
tail = tail->next;
list2 = list2->next;
}
}
//若有一个链表为空,则连接另一个
if(list1)
{
tail->next = list1;
}
else
{
tail->next = list2;
}
struct ListNode* ret = newhead->next;
free(newhead);
newhead = tail = NULL;
return ret;
}
统计链表长度,计算出中间位置;再寻找中间位置
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* cur = head;
int len = 0;
while(cur)
{
len++;
cur = cur->next;
}
int count = 0;
cur = head;
while(count < (len / 2))
{
count++;
cur = cur->next;
}
return cur;
}
快慢指针法:一个指针一次走一步,一个指针一次走两步。当快指针尾空或者快指针的next为空,那么慢指针所指向的元素就是中间元素。
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead->val = -1;
newHead->next = NULL;
while(head)
{
//先记录后继节点
struct ListNode* next = head->next;
//头插
head->next = newHead->next;
newHead->next = head;
//节点后移
head = next;
}
return newHead->next;
}
原地直接反转
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* next = NULL;
struct ListNode* prev = NULL;
struct ListNode* cur = head;
while(cur)
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* minHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* maxHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* minTail = minHead;
struct ListNode* maxTail = maxHead;
struct ListNode* cur = head;
while(cur)
{
if(cur->val < x)
{
minTail->next = cur;
minTail = minTail->next;
}
else
{
maxTail->next = cur;
maxTail = maxTail->next;
}
cur = cur->next;
}
//防止成环
maxTail->next = NULL;
minTail->next = maxHead->next;
struct ListNode* ret = minHead->next;
free(minHead);
free(maxHead);
return ret;
}
思路:倒数第k就是正数第n-k+1个(n为链表长度)
特殊情况:
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k) {
struct ListNode* cur = pListHead;
int len = 0;
//求链表的长度
while (cur)
{
len++;
cur = cur->next;
}
//特殊情况判断
//1.k不能大于链表长度
//2.k不能为0
//3.链表不为空
if (k > len || k == 0 || pListHead == NULL)
{
return NULL;
}
//倒数第k个就是正数第n-k+1个
int n = 1;
len = len - k + 1;
cur = pListHead;
while (n != len)
{
n++;
cur = cur->next;
}
return cur;
}
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
struct ListNode* fast = pListHead;
struct ListNode* slow = pListHead;
//快指针先走k步
while(k--)
{
//fast不能走出链表(k符合)
if(fast)
{
fast = fast->next;
}
else
{
return NULL;
}
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
typedef struct ListNode ListNode;
//创建节点
ListNode* CreatNode(int x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->val = x;
newnode->next = NULL;
return newnode;
}
//构建环
ListNode* CreatCircle(int n)
{
ListNode* head = CreatNode(1);
ListNode* tail = head;
//连续创建节点
for(int i=2; i<=n; i++)
{
ListNode* newnode = CreatNode(i);
//连接节点
tail->next = newnode;
tail = tail->next;
}
//成环
tail->next = head;
//返回尾节点的目的是:防止第一个元素就是要删除的元素
return tail;
}
int ysf(int n, int m ) {
ListNode* prev = CreatCircle(n);
ListNode* cur = prev->next;
int count = 1;
//有多个节点继续报数,直到剩下一个节点
while(cur->next != cur)
{
//逢m就删除
if(count == m)
{
prev->next = cur->next;
free(cur);
cur = prev->next;
count = 1;
}
else
{
prev = cur;
cur = cur->next;
count++;
}
}
return cur->val;
}
思路:从链表的中间节点逆置后半段,然后比较前半段与后半段是否相等。
//找中间节点
ListNode* FindMid(ListNode* A)
{
ListNode* fast = A;
ListNode* slow = A;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
//反转
ListNode* Reverse(ListNode* mid)
{
ListNode* cur = mid;
ListNode* prev = NULL;
ListNode* next = NULL;
while(cur)
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
bool chkPalindrome(ListNode* A) {
ListNode* mid = FindMid(A);
ListNode* midhead = Reverse(mid);
while(midhead)
{
if(A->val == midhead->val)
{
A = A->next;
midhead = midhead->next;
}
else
{
return false;
}
}
return true;
}
将链表A中的每一个节点与链表B中的每一个节点比较,看是否相等。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA = headA;
struct ListNode* curB = headB;
while(curA)
{
curB = headB;
while(curB)
{
//若节点相等,直接返回相等节点
if(curA == curB)
{
return curA;
}
curB = curB->next;
}
curA = curA->next;
}
//A中每一个节点都与B比较完毕,仍无交点
return NULL;
}
分别计算两链表长度,长的先走长度差步,然后再一起走,判断是否相等。
struct ListNode* getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA = headA;
struct ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
//先计算链表各自的长度,都少计算一个
while(curA->next)
{
lenA++;
curA = curA->next;
}
while(curB->next)
{
lenB++;
curB = curB->next;
}
//若不相交,直接返回空
if(curA != curB)
{
return NULL;
}
//算长度差
int gap = abs(lenA - lenB);
struct ListNode* longList = headA;
struct ListNode* shortList = headB;
if(lenA < lenB)
{
longList = headB;
shortList = headA;
}
//长的先走长度差步
while(gap--)
{
longList = longList->next;
}
//同时走,找交点
while(longList && shortList)
{
if(longList == shortList)
{
return shortList;
}
longList = longList->next;
shortList = shortList->next;
}
return NULL;
}
bool hasCycle(struct ListNode *head) {
struct ListNode * fast = head;
struct ListNode * slow = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
return true;
}
}
return false;
}
为什么不是一个走1步一个走3步?一个走1步一个走4步?一个走1步一个走6步?…
若N为奇数,C-1也为奇数则永远追不上(存在这种情况吗?)
思路:快慢指针,找到二者的相遇点。再使用两指针,从相遇点和链表头开始走,二者相遇点就是入环点
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
struct ListNode* meet = slow;
while(meet != head)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
原理
第二步:搞清random指向
新链表random就是原链表random的next!!!
第三步:将新链表从原链表上摘下来
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
//插入新节点
while(cur)
{
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
//连接新节点
newnode->val = cur->val;
newnode->next = cur->next;
cur->next = newnode;
//原链表后移
cur = cur->next->next;
}
//random
cur = head;
while(cur)
{
struct Node* newnode = cur->next;
if(cur->random == NULL)
{
newnode->random = NULL;
}
else
{
newnode->random = cur->random->next;
}
cur = cur->next->next;
}
//摘新链表
struct Node* newhead = (struct Node*)malloc(sizeof(struct Node));
newhead->next = NULL;
newhead->random = NULL;
struct Node* tail = newhead;
cur = head;
while(cur)
{
//尾插新链表
struct Node* newnode = cur->next;
tail->next = newnode;
tail = tail->next;
//恢复原链表
cur->next = newnode->next;
cur = cur->next;
}
return newhead->next;
}