LeetCode(数据结构入门题单——链表部分)

前两天去了曲江书城,看了一上午阿西莫夫的银河帝国系列

感觉已经喜欢上了那里,以后抽空趁没有疫情的时候还要去


链表:7~8天

主要是一些对于链表,最基本数据结构的基本操作

有一些题还是需要写写画画的,例如反转链表,第一次学的时候就是很久搞不明白

目录

141. 环形链表

21. 合并两个有序链表

203. 移除链表元素

206. 反转链表

83. 删除排序链表中的重复元素



141. 环形链表

难度简单1530收藏分享切换为英文接收动态反馈

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引 。 

进阶:你能用 O(1)(即,常量)内存解决此问题吗?

 方法一:首先发现是找环问题,那么环,再次出现,意味着可以用哈希表unordered_map来进行判断,遍历链表,当出现已经遍历过的结点,则说明,出现了环

时间复杂度,空间复杂度均为O(N)

/**
 * 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) 
	{
    	unordered_set<ListNode	*>set;
		while(head)
		{
			if(set.count(head))
				return	true;
			set.insert(head);
			head=head->next;	
		}    
        return false;
    }
};

方法二:追及问题,判断是否有环

用两个指针,一个跑的快(next->next),一个跑的慢(next),同时遍历链表,如果链表中有环,那么两个指针必会在环上相遇

时间复杂度O(N),空间复杂度O(1)

class Solution {
public:
    bool hasCycle(ListNode* head) {
        if (head == nullptr || head->next == nullptr) {
            return false;
        }
        ListNode* slow = head;
        ListNode* fast = head->next;
        while (slow != fast) {
            if (fast == nullptr || fast->next == nullptr) {
                return false;
            }
            slow = slow->next;
            fast = fast->next->next;
        }
        return true;
    }
};


 

21. 合并两个有序链表

难度简单2504收藏分享切换为英文接收动态反馈

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

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列

使用递归,将各个结点连接,建立一条新链表的过程

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) 
    {
  		if(list1==NULL)
			return list2;
		else	if(list2==NULL)
		 	return  list1;
		else	if(list1->val<list2->val)
		{
			list1->next=mergeTwoLists(list1->next,list2);
			return	list1;	
		}  
		else
		{
			list2->next=mergeTwoLists(list2->next,list1);
			return	list2;	
		}    
		
    }
};

 

203. 移除链表元素

难度简单950收藏分享切换为英文接收动态反馈

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

 非常巧妙地递归解法,也源于链表本身就有递归的性质

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if(head==NULL)
            return  head;
        head->next=removeElements(head->next,val);
        return head->val==val?head->next:head;
    }
};

 

206. 反转链表

难度简单2603收藏分享切换为英文接收动态反馈

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

经典解法是一个割裂逆置法,相当于先逆置前2个,再逆置前3个,这样一直逆置下去,如果用递归其实是相同的思路

这里只给出常见的递推解法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) 
    {
        ListNode    *pre=nullptr;
        ListNode    *cur=head;
        while(cur)
        {
            ListNode    *nex=cur->next;
            cur->next=pre;
            pre=cur;
            cur=nex;
        }
        return  pre;
    }
};

 

83. 删除排序链表中的重复元素

难度简单813收藏分享切换为英文接收动态反馈

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

示例 1:

输入:head = [1,1,2]
输出:[1,2]

示例 2:

输入:head = [1,1,2,3,3]
输出:[1,2,3]

提示:

  • 链表中节点数目在范围 [0, 300] 内
  • -100 <= Node.val <= 100
  • 题目数据保证链表已经按升序 排列

 简单水题

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) 
    {
        if(!head)
            return  head;
  		ListNode*	p=head;
		while(p->next)
		{
			if(p->val==p->next->val)
			{
				p->next=p->next->next;			
			}
			else
				p=p->next;
		}      
		return	head;
    }
};

 链表由于其自身结构特性,有大量运用递归的算法,今后需要注意

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值