牛客面试必刷101——链表

1.链表


1.反转链表:

单链表反转https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=295&tqId=23286&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路一:利用栈的后进先出的特点
//此题可以先让所有结点入栈,再出栈的时候进行链接
//空间复杂度 O(N)	时间复杂度O(N)
 class Solution {
 public:
 	ListNode* ReverseList(ListNode* pHead) {
 		stack<ListNode*> sL;
 		while (pHead)
 		{
 			sL.push(pHead);
 			pHead = pHead->next;
 		}
 		if (sL.empty())
 			return nullptr;
 		ListNode* first = sL.top();
 		ListNode* next = first;
 		while (1)
 		{
 			sL.pop();
 			if (sL.empty())
 				break;
 			ListNode* temp = sL.top();
 			next->next = temp;
 			next = next->next;
 		}
 		next->next = nullptr;
 		return first;
 	}
 };
//思路二:双指针
//记录第一个节点和下一个节点,改变其指向
//空间复杂度 O(1)	时间复杂度O(N)
class Solution {
public:
	ListNode* ReverseList(ListNode* pHead) {
		ListNode* newHead = nullptr;
		while (pHead)
		{
			ListNode* tmp = pHead->next;
			pHead->next = newHead;
			newHead = pHead;
			pHead = tmp;
		}
		return newHead;
	}
};

 

n到m链表反转https://www.nowcoder.com/practice/b58434e200a648c589ca2063f1faf58c?tpId=295&tqId=654&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路一:四指针
// 记录需要反转区间的前一个prev及需要反转的下一个left
// 记录需要反转区间的最后一个right及下一个cur
// 时间复杂度: O(N)  空间复杂度O(1)
class Solution {
public:
	void reverseList(ListNode* head){
		ListNode* phead = nullptr;
		ListNode* cur = head;
		while (cur)
		{
			ListNode* tmp = cur->next;
			cur->next = phead;
			phead = cur;
			cur = tmp;
		}
	}
	ListNode* reverseBetween(ListNode* head, int m, int n) {
		ListNode* phead = new ListNode;
		phead->val = -1;
		phead->next = head;

		ListNode* prev = phead;
		for (int i = 0; i < m - 1; i++)
		{
			prev = prev->next;
		}
		ListNode* left = prev->next;
		ListNode* right = prev;
		for (int i = 0; i < n - m + 1; i++)
		{
			right = right->next;
		}
		ListNode* cur = right->next;
		right->next = nullptr;
		prev->next = nullptr;

		reverseList(left);

		prev->next = right;
		left->next = cur;
		return phead->next;
		// write code here
	}
};

//思路二:双指针
//直接改变各指针指向
//时间复杂度: O(N)  空间复杂度O(1)
class Solution
{
public:
	ListNode* reverseBetween(ListNode* head, int m, int n)
	{
		ListNode* phead = new ListNode;
		phead->val = -1;
		phead->next = head;
		ListNode* prev = phead;
		for (int i = 1; i <= m - 1; i++)
		{
			prev = prev->next;
		}
		ListNode* cur = prev->next;

		for (int i = 1; i <= n - m; i++)
		{
			ListNode* CurNext = cur->next;
			cur->next = CurNext->next;
			CurNext->next = prev->next;
			prev->next = CurNext;

		}
		return phead->next;
	}
};

k个节点反转https://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e?tpId=295&tqId=722&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路和上面翻转(n.m)链表思路同
class Solution {
public:
	ListNode* reverseKGroup(ListNode* head, int k) {
		int n = 0;
		ListNode* num_head = head;
		while (num_head)
		{
			num_head = num_head->next;
			++n;
		}
		n /= k;    //需要翻转次数
		ListNode* phead = new ListNode(-1);
		phead->next = head;
		ListNode* prev = phead;
		ListNode* cur = prev->next;
		while (n--)
		{
			for (int i = 1; i < k; i++)
			{
				ListNode* cur_next = cur->next;    //将需要翻转的往前链接
				cur->next = cur_next->next;
				cur_next->next = prev->next;
				prev->next = cur_next;
			}
			prev = cur;
			cur = cur->next;
		}
		return phead->next;
		// write code here
	}
};

  2.合并链表


合并有序链表https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337?tpId=295&tqId=23267&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路:双指针
//每次比较节点值大小,依次链接到新的链表
//时间复杂度O(N) 空间复杂度O(1)
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        ListNode*p1=pHead1;
		ListNode*p2=pHead2;
		ListNode*npHead=new ListNode(-1);
		ListNode*cur=npHead;
		while(p1)
		{
			if(p1->val<p2->val || p2==nullptr)
			{
				cur->next=p1;
				p1=p1->next;
				cur=cur->next;
			}
			else if(p1->val>=p2->val || p1==nullptr)
			{
				cur->next=p2;
				p2=p2->next;
				cur=cur->next;
			}
		}
		if(p2) cur->next=p2;	//p2不为nullpt直接链接剩下的
		return npHead->next;
    }
};

 

 合并K个有序链表

 //思路一:
 //复用上题合并两个有序链表
 //第一次将lists[0]和lists[1]结合成一个大链表,再将大链表与后面链表依次合并
class Solution {
  public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        ListNode* p1 = pHead1;
        ListNode* p2 = pHead2;
        ListNode* npHead = new ListNode(-1);
        ListNode* cur = npHead;
        while (p1) {
            if (p1->val < p2->val || p2 == nullptr) {
                cur->next = p1;
                p1 = p1->next;
                cur = cur->next;
            } else if (p1->val >= p2->val || p1 == nullptr) {
                cur->next = p2;
                p2 = p2->next;
                cur = cur->next;
            }
        }
        if (p2) cur->next = p2;
        return npHead->next;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(!lists.size())   return nullptr;
        int m = 1;
        ListNode* p1=lists[0];
        while(m<lists.size())
            p1=Merge(p1, lists[m++]);
        return p1;
    }
};
//思路二:
//先将需要排序在vector进行存储,sort后再重建链表
//时间复杂度O(N*logN)   空间复杂度O(N) 
class Solution {
public:
	ListNode* mergeKLists(vector<ListNode*>& lists) {
		vector<int> vi;
		for (int i = 0; i < lists.size(); i++)
		{
			ListNode* phead = lists[i];
			while (phead)
			{
				vi.push_back(phead->val);
				phead = phead->next;
			}
		}
		sort(vi.begin(), vi.end(), [](int a, int b) {return a < b; });
		ListNode* head = new ListNode(-1);
		ListNode* cur = head;
		for (int i = 0; i < vi.size(); i++)
		{
			ListNode* newNode = new ListNode(vi[i]);
			cur->next = newNode;
			cur = newNode;
		}
		return head->next;
	}
};

3.链表中环的问题

判断链表是否有环https://www.nowcoder.com/practice/650474f313294468a4ded3ce0f7898b9?tpId=295&tqId=605&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路:快慢指针
 //快指针比慢指针每次多走一步
 //如果有环快指针则会追上慢指针,无环则先到nullptr
 //时间复杂度O(N)  空间复杂度O(1)
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode*slow=head,*fast=head;
        while(fast && fast->next)   //快指针先到尾--这里可以判断head为nullptr和节点只有一个的情况
        {
            slow=slow->next;
            fast=(fast->next)->next;
            if(fast==slow)
                return true;
        }
        return false;
    }
};

环的入口https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=295&tqId=23449&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路一:同上采用快慢指针
//只要有环,必定相交两次,即第二次为入口
//时间复杂度O(N) 空间复杂度O(1)
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        ListNode*slow=pHead,*fast=pHead;
        while(fast && fast->next)
        {
            slow=slow->next;
            fast=(fast->next)->next;
            if(slow == fast) break;
        }
        if(fast == nullptr || fast->next == nullptr) return nullptr;
        fast = pHead;
        while(fast != slow)
        {
            fast=fast->next;
            slow=slow->next;
        }
        return fast;
    }
};
 //思路:哈希表
 //相同的结点会在哈希表出现两次,判断第一个出现两次的即可
 //时间复杂度 O(N)  空间复杂度 O(N)
 class Solution {
 public:
     ListNode* EntryNodeOfLoop(ListNode* pHead) {
         unordered_map<ListNode*, int> um_count;
         while (pHead)
         {
             ++um_count[pHead];
             if (um_count[pHead] == 2)
                 return pHead;
             pHead = pHead->next;
         }
         return nullptr;
     }
 };

删除倒数第n个节点https://www.nowcoder.com/practice/f95dcdafbde44b22a6d741baf71653f6?tpId=295&tqId=727&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

 //思路:双指针
 //先找到需要删除节点的前一个,再链接下一个的下一个
 //时间复杂度 O(N) 空间复杂度 O(1)
 class Solution {
 public:
     ListNode* removeNthFromEnd(ListNode* head, int n) {
         ListNode* phead = new ListNode(-1);
         phead->next = head;
         ListNode* slow = phead, * fast = head; //让slow指向要删除的前一个
         while (--n && fast->next) fast = fast->next;
         while (fast->next)
         {
             slow = slow->next;
             fast = fast->next;
         }
         slow->next = (slow->next)->next;
         return phead->next;
     }
 };

 链表相交https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tpId=295&tqId=23257&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

 //思路:双指针
 //两个指针所走路径同,速度同,所以必定相交
 //时间复杂度O(n+m) 空间复杂度O(1)
 class Solution {
 public:
	 ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
		 ListNode* p1 = pHead1, * p2 = pHead2;
		 while (p1 != p2)
		 {
			 p1 = (p1 == nullptr) ? pHead2 : p1->next;	//走完第一条链,走第二条
			 p2 = (p2 == nullptr) ? pHead1 : p2->next;	//走完第二条链,走第一条
		 }
		 return p1;	
	 }
 };

链表相加https://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b?tpId=295&tqId=1008772&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

 思路:反转相加
 复用前面反转链表代码
 时间复杂度O(N) 空间复杂度O(1)
 class Solution {
 public:
     ListNode* Reverse(ListNode* head)
     {
         ListNode* phead = nullptr;
         ListNode* cur = head;
         while (cur)
         {
             ListNode* next = cur->next;
             cur->next = phead;
             phead = cur;
             cur = next;
         }
         return phead;
     }
     ListNode* addInList(ListNode* head1, ListNode* head2) {
         head1 = Reverse(head1);
         head2 = Reverse(head2);
         ListNode* phead = new ListNode(-1);
         int scale = 0;
         while (head1 || head2 || scale)
         {
             int val = scale;
             if (head1)
             {
                 val += head1->val;
                 head1 = head1->next;
             }
             if (head2)
             {
                 val += head2->val;
                 head2 = head2->next;
             }
             scale = val / 10;
             ListNode* cur = new ListNode(val % 10);
             ListNode* next = phead->next;
             phead->next = cur;
             cur->next = next;
         }
         return phead->next;
     }
 };

链表排序(升序)https://www.nowcoder.com/practice/f23604257af94d939848729b1a5cda08?tpId=295&tqId=1008897&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295 

//思路:参考希尔排序
//时间复杂度O(N*logN) 空间复杂度O(logN)因为递归最坏为树形结构,即为logN
class Solution {
public:
    ListNode* sortDouble(ListNode* head1, ListNode* head2)
    {
        if (head1 == nullptr)
            return head2;
        if (head2 == nullptr)
            return head1;
        ListNode* phead = new ListNode(-1);
        ListNode* cur = phead;
        while (head1 && head2)
        {
            if (head1->val < head2->val)
            {
                cur->next = head1;
                head1 = head1->next;
            }
            else
            {
                cur->next = head2;
                head2 = head2->next;
            }
            cur = cur->next;
        }
        if (head1)
            cur->next = head1;
        if (head2)
            cur->next = head2;
        return phead->next;
    }

    ListNode* sortInList(ListNode* head) {
        //走到只剩一个元素或为nullptr时,必定有序
        if (head == nullptr || head->next == nullptr)
            return head;
        ListNode* slow = head;
        ListNode* mid = head->next;
        ListNode* fast = head->next->next;
        while (fast && fast->next)
        {
            slow = slow->next;
            mid = mid->next;
            fast = fast->next->next;    //right走两步,先到终点
        }
        slow->next = nullptr; //中间断开
        //右边指针到达末尾时,中间指针指向链表中间
        return sortDouble(sortInList(head), sortInList(mid));
        //再以头为head1和中间断开结点为head2继续分治
    }
};

链表回文https://www.nowcoder.com/practice/3fed228444e740c8be66232ce8b87c2f?tpId=295&tqId=1008769&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路:快慢指针,逆序比较
//时间复杂度O(N) 空间复杂度O(1)
class Solution {
  public:
    /**
     *
     * @param head ListNode类 the head
     * @return bool布尔型
     */
    ListNode* Reverse(ListNode* head) {
        ListNode* phead = nullptr;
        ListNode* cur = head;
        while (cur) {
            ListNode* next = cur->next;
            cur->next = phead;
            phead = cur;
            cur = next;
        }
        return phead;
    }
    bool isPail(ListNode* head) {
        ListNode* mid = new ListNode(-1);
        ListNode* fast = head;
        ListNode* slow = head;
        mid->next = slow;
        while (fast && fast->next) {
            mid = mid->next;
            slow = slow->next;
            fast = fast->next->next;
        }
        mid->next = nullptr;
        head=Reverse(head);
        if(head->val != slow->val)  //节点个数为单数情况,则往后退一个再比较
            slow=slow->next;
        while (head && slow) {
            if(head->val != slow->val)
                return false;
            head = head->next;
            slow = slow->next;
        }
        return true;
    }
};

链表的奇偶重排https://www.nowcoder.com/practice/02bf49ea45cd486daa031614f9bd6fc3?tpId=295&tqId=1073463&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路:借助辅助数组
//时间复杂度O(N) 空间复杂度O(1)
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        vector<int> vL;
        while (head)
        {
            vL.push_back(head->val);
            head = head->next;
        }
        ListNode* phead = new ListNode(-1);
        ListNode* cur = phead;
        for (int i = 0; i < vL.size(); i += 2)
        {
            cur->next = new ListNode(vL[i]);
            cur = cur->next;
        }
        for (int i = 1; i < vL.size(); i += 2)
        {
            cur->next = new ListNode(vL[i]);
            cur = cur->next; 
        }
        return phead->next;
    }
};


//存储方式2:
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        vector <ListNode*> vL;
        while (head)
        {
            vL.push_back(head);
            head = head->next;
        }
        ListNode* phead = new ListNode(-1);
        ListNode* cur = phead;
        for (int i = 0; i < vL.size(); i += 2)
        {
            cur->next = vL[i];
            cur = cur->next;
        }
        for (int i = 1; i < vL.size(); i += 2)
        {
            cur->next = vL[i];
            cur = cur->next; 
        }
        cur->next=nullptr;  //这一步很重要!!!存储节点会把节点后面的所有节点都记录
        return phead->next;
    }
};

删除链表重复数https://www.nowcoder.com/practice/c087914fae584da886a0091e877f2c79?tpId=295&tqId=664&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//思路:双指针
//时间复杂度O(N) 空间复杂度O(1)
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == nullptr)
            return nullptr;
        ListNode* phead = new ListNode(-1);
        phead->next = head;
        ListNode* slow = phead;
        ListNode* fast = head;
        while (fast)
        {
            if (slow->val == fast->val)
            {
                fast = fast->next;
                continue;
            }
            else
            {
                slow->next = fast;
                slow = fast;
                fast = fast->next;
            }
        }
        slow->next=nullptr;
        return phead->next;
    }
};

删除链表相同项https://www.nowcoder.com/practice/71cef9f8b5564579bf7ed93fbe0b2024?tpId=295&tqId=663&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

//时间复杂度O(N) 空间复杂度O(1)
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == nullptr)
            return nullptr;
        ListNode*phead=new ListNode(-1);
        phead->next=head;
        ListNode*cur=phead;
        while(cur->next && cur->next->next)
        {
            if(cur->next->val == cur->next->next->val)
            {
                int tmp = cur->next->val;
                while(cur->next && cur->next->val == tmp)
                    cur->next = cur->next->next;
            }
            else {
                cur=cur->next;
            }
        }
        return phead->next;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值