leetcode-链表-简单-C

序号21

题目:将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

解析:这是无头节点的
1.双指针
先按有头节点做,最后头节点向后移,也可叫做伪头节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    
    
    struct ListNode *r, *preHead;
    preHead = (struct ListNode*)malloc(sizeof(struct ListNode));
    r = preHead;
    while (l1 && l2)
    {
    
    
        if (l1->val <= l2->val)
        {
    
    
            r->next = l1;
            l1 = l1->next;
        }
        else
        {
    
    
            r->next = l2;
            l2 = l2->next;
        }
        r = r->next;
    }
    r->next = l1 ? l1 : l2;
    r = preHead->next;
    free(preHead);
    return r;
}

序号83

题目:给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

解析

  1. 模拟
    设置双指针,相同就删除,防止断链就行
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* deleteDuplicates(struct ListNode* head){
    
    
    if (head == NULL)
        return head;
    struct ListNode *p, *q, *r;
    p = head;
    q = head->next;
    while (q != NULL)
    {
    
    
    	if (p->val == q->val)
    	{
    
    
    		r = q->next;
    		p->next = r;
    		free(q);
    		q = r;
    	}
    	else
    	{
    
    
    		p = q;
    		q = q->next;
    	}
    }
    return head;
}

序号141

题目:给定一个链表,判断链表中是否有环。

解析

  1. 快慢指针
    快指针每次多走一步,如果有环,就会与慢指针相遇
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    
    
    if (head == NULL || head->next == NULL)
    	return false;

    struct ListNode *slow, *fast;
    slow = head;
    fast = head->next;
    while (slow != fast)
    {
    
    
    	if (fast == NULL ||fast->next == NULL)
    		return false;
    	slow = slow->next;
    	fast = fast->next->next;
    }
    return true;
}

序号160

题目:编写一个程序,找到两个单链表相交的起始节点。

解析

  1. 尾部对齐
    较长的链表指针前移到与短链表相同长度的位置,双方同时前进,找到交叉点
  2. 成环,双指针
    若两者不相交,各自走完两端链表都刚好到空
    若相交且长度不同,必要走对方的链表。相交的部分都要走一遍,剩下部分的长度叠加,各自要走一遍。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    
    
    if (headA == NULL || headB == NULL)
    	return NULL;
    struct ListNode *p = headA, *q = headB;
    
    while (p != q)
    {
    
    
    	p = p->next;
    	q = q->next;
    	if (p == NULL && q == NULL)
    		return NULL;
    	if (p == NULL)
    		p = headB;
    	else if (q == NULL)
    		q = headA;
    }
   	return p;
}

序号203

题目:删除链表中等于给定值 val 的所有节点。

解析

  1. 模拟
    设置一个伪头节点,模拟删除
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val){
    
    
    struct ListNode *pre, *p, *r, *preHead;
	preHead = (struct ListNode*)malloc(sizeof(struct ListNode));
	preHead->next = head;
    pre = preHead;
	p = head;
	while (p)
	{
    
    
		if (p->val != val)
		{
    
    
			pre = p;
			p = p->next;
		}
		else
		{
    
    
			r = p->next;
			free(p);
			pre->next = r;
			p = r;
		}
	}

    r = preHead->next;
    free(preHead);
	return r;
}

序号206

题目:反转一个单链表。

解析

  1. 头插法
    设置一个伪头结点,重新头插,记得 head->next 设置为 NULL,它是最后一个结点
  2. 模拟
    设置 3 个指针,按顺序反转
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head){
    struct ListNode *pre, *p, *t;
	pre = NULL;
	p = head;
	while (p)
	{
		t = p->next;
		p->next = pre;
		pre = p;
		p = t;
	}
	return pre;
}

序号234

题目:请判断一个链表是否为回文链表。

解析

  1. 数据写入一个数组中
    用数组判断回文
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool isPalindrome(struct ListNode* head){
    
    
    int len = 0, i, flag = 1;
	struct ListNode *p = head;

	for (; p; p = p->next)
		len++;
	int* arr = (int*)malloc(sizeof(int)*len);
	for (p = head, i = 0; p; p = p->next)
		arr[i++] = p->val;
	for (i = 0; i < len / 2; i++)
	{
    
    
		if (arr[i] != arr[len-1-i])
		{
    
    
			flag = 0;
			break;
		}
	}

	free(arr);
	return flag ? true : false;
}

序号237

题目:请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。

解析

  1. 与后面结点交换值,删除后面结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void deleteNode(struct ListNode* node) {
    
    
    struct ListNode *p;
    node->val = node->next->val;
    p = node->next;
    node->next = p->next;
    free(p);
}

序号876

题目:给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

解析

  1. 单指针
    先遍历一遍得到长度,第二遍得到
  2. 快慢指针
    快指针走两步,慢指针走一步,快指针到达终点时,慢指针就在中间
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* middleNode(struct ListNode* head){
    
    
	struct ListNode *slow, *fast;
	slow = fast = head;

	while (fast && fast->next)
	{
    
    
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}

序号1290

题目:给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。
请你返回该链表所表示数字的 十进制值 。

解析

  1. 进制转换
    和十进制相似,累乘 10 换成累乘 2
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int getDecimalValue(struct ListNode* head){
    
    
	int sum = 0;
	struct ListNode *p = head;
	while (p)
	{
    
    
		sum = sum * 2 + p->val;
		p = p->next;
	}
	return sum;
}

面试 02.01

题目:编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
提示:
链表长度在[0, 20000]范围内。
链表元素在[0, 20000]范围内。

解析

  1. 散列记录是否删除
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeDuplicateNodes(struct ListNode* head){
    
    
	if (head == NULL || head->next == NULL)
        return head;
    int *hash = (int*)calloc(20005,sizeof(int));
	struct ListNode* pre, *p, *temp;
	pre = head;  //第一个开始不会重复
    hash[head->val] = 1;  //第一个先加入
	p = head->next;
	while (p)  //从第二个开始判断
	{
    
    
		if (hash[p->val] != 0)
		{
    
    
			temp = p->next;
			free(p);
			p = temp;
			pre->next = p;
		}
		else
		{
    
    
			hash[p->val] = 1;
			pre = p;
			p = p->next;
		}
	}
	free(hash);
	return head;
}

面试02.02

题目:实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
给定的 k 保证是有效的。

解析

  1. 双指针
    设置间隔为 k 的双指针,第一个指针走到空,第二个便是答案
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int kthToLast(struct ListNode* head, int k){
    
    
    struct ListNode *slow, *fast;
    slow = fast = head;
    while (k--)
    	fast = fast->next;
    while (fast)
    {
    
    
    	slow = slow->next;
    	fast = fast->next;
    }
    return slow->val;
}

面试02.03

题目:实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点。

解析

  1. 交换与后面的值,删除后面那个结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void deleteNode(struct ListNode* node) {
    
    
    struct ListNode *p = node->next;
    node->val = p->val;
    node->next = p->next;
    free(p);
}

面试02.06

题目:编写一个函数,检查输入的链表是否是回文的。

解析

  1. 记录下链表的元素,用数组判断回文
  2. 快慢指针找到中间点和结尾点,反转后半部分,然后再回文判断

方法1:

bool isPalindrome(struct ListNode* head){
    
    
	int* hash = (int*)malloc(sizeof(int) * 10000);
	int cnt = 0;
	struct ListNode *p = head;
	while (p)
	{
    
    
		hash[cnt++] = p->val;
		p = p->next;
	}
	for (int i = 0; i < cnt/2; i++)
	{
    
    
		if (hash[i] != hash[cnt-1-i])
			return false;
	}
	free(hash);
	return true;
}

方法2:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool isPalindrome(struct ListNode* head){
    
    
    if (head == NULL || head->next == NULL)
        return true;
	struct ListNode *slow, *fast, *p, *q, *mid;
    p = slow = head;
    fast = head->next;
    while (fast && fast->next)
    {
    
    
        slow = slow->next;
        fast = fast->next->next;
    }
    mid = slow;
    p = slow->next;
    while (p)
    {
    
    
        q = p->next;
        p->next = slow;
        slow = p;
        p = q;
    }
    p = head;
    while (1)
    {
    
    
        if (p != mid)
        {
    
    
            if (p->val != slow->val)
                return false;
            else
            {
    
    
                p = p->next;
                slow = slow->next;
                continue;
            }
        }
        if (p == mid && slow == mid)
            return true;
        if (p == mid && slow->next == mid)
        {
    
    
            if (p->val == slow->val)
                return true;
            else
                return false;
        }
    }
    return true;
}

面试18

题目:给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。

解析

  1. 模拟删除
    设置一个 preHead,统一删除步骤
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* deleteNode(struct ListNode* head, int val){
    
    
	struct ListNode *pre, *p, *preHead;
	preHead = (struct ListNode *)malloc(sizeof(struct ListNode));
	preHead->next = head;
    pre = preHead;
	p = head;
	while (p)
	{
    
    
		if (p->val == val)
		{
    
    
			pre->next = p->next;
            head = preHead->next;
            free(preHead);
			return head;
		}
		pre = p;
		p = p->next;
	}
	return head;
}

猜你喜欢

转载自blog.csdn.net/qq_40860934/article/details/105166678
今日推荐