【数据结构】链表OJ题

面试题 02.04 分割链表

  • 定义lesshead和greaterhead链接小于和大于等于k的值
  • 分别设置哨兵位和尾节点指针
  • 最后将两表去除哨兵位再链接

在这里插入图片描述

struct ListNode* partition(struct ListNode* head, int x)
{
	struct ListNode* lesshead, * lesstail, * greaterhead, * greatertail;
	lesshead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode));
	lesstail->next = NULL;

	greaterhead = greatertail = (struct ListNode*)malloc(sizeof(struct ListNode));
	greatertail->next = NULL;

	struct ListNode* cur = head;
	while (cur)
	{
		if (cur->val < x)
		{
			lesstail->next = cur;
			lesstail = cur;
		}
		else
		{
			greatertail->next = cur;
			greatertail = cur;
		}
		cur = cur->next;
	}
	lesstail->next = greaterhead->next;
	greatertail->next = NULL;

	struct ListNode* newhead = lesshead->next;

	free(lesshead);
	free(greaterhead);
	return newhead;
}

 

剑指 Offer II 027 回文链表

  • 先找到链表中间节点
  • 将中间节点以后的节点从原链表截断逆置生成新链表
  • 与原链表逐节点的值相比较
    在这里插入图片描述
//回文结构
bool isPalindrome(struct ListNode* head) {
	if (head == NULL)
	{
		return false;
	}

	//找中间节点
	struct ListNode* cur = head, * slow = head, * fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	struct ListNode* mid = slow;

	//将中间节点之后的顺序反转
	struct ListNode* newhead = slow;
	cur = newhead;
	struct ListNode* prev = NULL;
	while (cur)
	{
		struct ListNode* next = cur->next;
		cur->next = prev;
		prev = cur;
		cur = next;
	}
	newhead = prev;

	//遍历两组链表,检查是否每位相等
	struct ListNode* cur2 = newhead;
	struct ListNode* cur1 = head;
	while (cur1 && cur2)
	{
		if (cur1->val != cur2->val)
		{
			return false;
		}
		cur1 = cur1->next;
		cur2 = cur2->next;
	}
	return true;
}

 

206. 反转链表

在这里插入图片描述

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL)
    {
        return NULL;
    }
    struct ListNode* cur = head, * n2 = head;
    struct ListNode* n1 = cur;
    //记录首元素next,后将其置空
    n2 = cur->next;
    cur->next = NULL;
    cur = n2;
    while (cur)
    {
        //n2提前记录下一元素地址
        n2 = cur->next;
        //当前元素next指向已反转的头
        cur->next = n1;
        //更新已反转的头
        n1 = cur;
        //更新cur至下一待反转元素
        cur = n2;
    }
    struct ListNode* nhead = n1;
    return nhead;
}

 

160 相交链表

  • 根据两链表长度求出长度差k
  • 较长的链表先走k步
  • 两表再一起走,节点地址相同时返回此节点
 int ListSize(struct ListNode * head)
 {
     struct ListNode * cur=head;
     int len=0;
     while(cur)
    {
        len++;
        cur=cur->next;
    }
    return len;
 }
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int len1=ListSize(headA);
    int len2=ListSize(headB);
    int k=abs(len1-len2);
    struct ListNode * longlist=headA;
    struct ListNode * shortlist=headB;
    if(len1<len2)
    {
        longlist=headB;
        shortlist=headA;
    }
    struct ListNode * cur1=longlist, *cur2=shortlist;
    while(k--)
    {
        cur1=cur1->next;
    }
    while(cur1 && cur2)
    {
        if(cur1==cur2)
        {
            return cur1;
        }
        cur1=cur1->next;
        cur2=cur2->next;
    }
    return NULL;
}

 

141 环形链表

快慢指针法,相遇则为环形链表

//环形链表,快慢指针法
bool hasCycle(struct ListNode* head) {
	struct ListNode* slow = head;
	struct ListNode* fast = head;
	while (fast && fast->next)
	{

		fast = fast->next->next;
		slow = slow->next;
		if (slow == fast)
		{
			return true;
		}
	}
	return false;
}

142 环形链表 II

  • 先找到入环点
  • 相遇点到入环点的距离等于链头到入环点的距离
  • 从链头和相遇点出发,相遇点即为入环点

在这里插入图片描述

//环形链表 II
//找到入环点,再判断环形链表代码块内续写
struct ListNode* detectCycle(struct ListNode* head) {
	struct ListNode* slow = head, * fast = head, * meet = NULL;
	while (fast && fast->next)
	{
		//找到快慢指针相遇点
		fast = fast->next->next;
		slow = slow->next;
		//相遇点到入环点的距离等于链头到入环点的距离
		if (slow == fast)
		{
			meet = slow;
			while (meet != head)
			{
				meet = meet->next;
				head = head->next;
			}
			return meet;
		}
	}
	return NULL;
}

138 复制带随机指针的链表

  • 在原链表每个节点后复制一个节点
  • 根据原节点设置复制节点的random
    • 注意不可复制节点的同时处理random,因为random指向位置还未完成复制
  • 将处理好的复制节点链接到newhead
    在这里插入图片描述
//复制带随机指针的链表
struct Node* copyRandomList(struct Node* head) {
	struct Node* cur = head;
	//在原链表每个节点后复制一个节点
	while (cur)
	{
		struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
		copy->val = cur->val;
		copy->next = cur->next;
		cur->next = copy;
		cur = copy->next;
	}
	cur = head;
	struct Node* next = NULL;
	//根据原节点设置复制节点的random
	while (cur)
	{
		struct Node* copy = cur->next;
		next = copy->next;
		if (cur->random == NULL)
		{
			copy->random = NULL;
		}
		else
		{
			copy->random = cur->random->next;
		}
		cur = next;
	}
	//将处理好的复制节点链接到newhead
	cur = head;
	struct Node* newtail = NULL, * newhead = NULL;
	while (cur)
	{
		struct Node* copy = cur->next;
		next = copy->next;
		if (newtail == NULL)
		{
			newhead = newtail = copy;
		}
		else
		{
			newtail->next = copy;
			newtail = copy;
		}
		cur->next = next;
		cur = next;
	}
	return newhead;
}

 

147. 对链表进行插入排序

  • {3, 2, 1, 4, 1, 0}为例
  • 若大于后一个节点值,则后移
  • 3遇到4时停止,
  • 这样一来4前面可成功排序
  • 但4之后的节点如果比较小,也不会回到4之前
  • 通过将整个排序过程循环len次可成功排序
    在这里插入图片描述
    自写代码
//147. 对链表进行插入排序
struct ListNode* insertionSortList(struct ListNode* head) {
	if (head == NULL)
	{
		return NULL;
	}
	struct ListNode* ehead = (struct ListNode*)malloc(sizeof(struct ListNode));
	if (ehead == NULL)
	{
		exit(-1);
	}
	ehead->next = head;
	head = ehead;
	struct ListNode* prev = ehead, * cur = ehead->next, * next = NULL;
	int len = 0;
	while (cur)
	{
		len++;
		cur = cur->next;
	}
	while (len--)
	{
		cur = ehead->next;
		next = NULL;
		prev = ehead;
		while (cur->next)
		{
			int flag = 0;
			next = cur->next;
			struct ListNode* tmp = cur, * tmpprev = prev, * tmpnext = next;
			struct ListNode* tmpcur = cur;
			while (tmp->next)
			{
				if (tmp->val > tmpnext->val)
				{
					flag = 1;

					tmp->next = tmpnext->next;
					tmpnext->next = tmp;
					tmpprev->next = tmpnext;
				}
				else
				{
					break;
				}
				tmpprev = tmpnext;
				tmpnext = tmp->next;

			}
			if (flag == 0)
			{
				prev = cur;
			}
			if (flag == 1)
			{
				prev->next = next;
			}
			cur = next;
		}
	}
	
	head = ehead->next;
	free(ehead);
	ehead = NULL;
	return head;
}
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值