牛客网刷题笔记——链表

反转链表
描述
输入一个链表,反转链表后,输出新链表的表头。
输入:	{41,2,3}
返回值:	{3,2,14}

本题看似是一道很简单的题,很多人刷题之路可能是从这道题开始,但如果不看题解,能独立想清楚却并不是那么容易,此题考查的是通过对链表指针的操作,实现链表反转。建议看完实现思路后,自己画一遍过程。
实现思路

使用三个指针,来实现
1、cur指针指向待反转链表的第一个节点
2、pre指针指向已反转链表的最后一个节点
3、nex指针用以保存待反转链表的下一个节点

实现过程:
1、记录下一个节点的位置 nex=cur-> next
2、当前带反转链表的第一个节点的next指向已反转链表的最后一个节点 cur->next=pre
3、更新指针位置 pre=cur cur=nex

循环终止条件:cur=nullptr

示例代码

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode* cur=pHead;
        ListNode* pre=nullptr;
        ListNode* nex=nullptr;
        while(cur){
            nex=cur->next;//保存位置
            cur->next=pre;
            pre=cur;
            cur=nex;
        }
        return pre;
    }
};
判断链表是否有环
/**
 * 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) {
        //判断链表是否有环,使用快慢指针法
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast&&fast->next){
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow){
                return true;
            }
        }
        return false;
        
    }
};
链表相加生成相加链表

方法一:头插法(不使用新的栈保存临时的值)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head1 ListNode类 
     * @param head2 ListNode类 
     * @return ListNode类
     */
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        // write code here
        // 为了对齐位置,我们先使用栈分别保存两个链表中节点的值
        stack<int> stk1;
        stack<int> stk2;
        ListNode* head=new ListNode(-1);
        ListNode* tail=head;
        while(head1){
            stk1.push(head1->val);
            head1=head1->next;
        }
        while(head2){
           stk2.push(head2->val);
           head2=head2->next;
        }
        int carry=0; //考虑进位
        while(!stk1.empty()||!stk2.empty()||carry!=0){
            int a=0,b=0;
            if(!stk1.empty()){
                a=stk1.top();
                stk1.pop();
            }
            if(!stk2.empty()){
                b=stk2.top();
                stk2.pop();
            }
            int sum=a+b+carry;
            int num=sum%10;
            carry=sum/10;
            ListNode* tmp=new ListNode(num);
            tmp->next=head->next;
            head->next=tmp;
        }
        return head->next;
        
    }
};

方法二:尾插法 注意头插和尾插的区别,头插逆序,尾插顺序

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head1 ListNode类 
     * @param head2 ListNode类 
     * @return ListNode类
     */
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        // write code here
        // 为了对齐位置,我们先使用栈分别保存两个链表中节点的值
        stack<int> stk1;
        stack<int> stk2;
        stack<int> stk3;
        ListNode* head=new ListNode(-1);
        ListNode* tail=head;
        while(head1){
            stk1.push(head1->val);
            head1=head1->next;
        }
        while(head2){
           stk2.push(head2->val);
           head2=head2->next;
        }
        int carry=0; //考虑进位
        while(!stk1.empty()||!stk2.empty()||carry!=0){
            int a=0,b=0;
            if(!stk1.empty()){
                a=stk1.top();
                stk1.pop();
            }
            if(!stk2.empty()){
                b=stk2.top();
                stk2.pop();
            }
            int sum=a+b+carry;
            int num=sum%10;
            carry=sum/10;
            stk3.push(num);
        }
        while(!stk3.empty()){
            ListNode* tmp=new ListNode(stk3.top());
            tail->next=tmp;
            tail=tmp;
            stk3.pop();
        }
        return head->next;
        
    }
};
链表中的节点 每K个反转一组
大致过程可以分解为
1、找到待翻转的k个节点(注意:若剩余数量小于 k 的话,则不需要反转,因此直接返回待翻转部分的头结点即可)。
2、对其进行翻转。并返回翻转后的头结点(注意:翻转为左闭又开区间,所以本次反转的尾结点其实就是下一反转的头结点)。
3、对下一轮 k 个节点也进行翻转操作。
4、将上一轮翻转后的尾结点指向下一轮翻转后的头节点,即将每一轮翻转的k的节点连接起来。

牛客网刷题笔记——链表_第1张图片

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    ListNode* reverseKGroup(ListNode* head, int k) {
        // write code here
        // 参考链表反转的思路
        if(!head||!head->next)
            return head;
        ListNode* tail=head;
        for(int i=0;i<k;i++){
            if(tail==nullptr){
                return head;
            }
            tail=tail->next;
        }
        //关键代码是接下来三行,注意理解
        ListNode* newHead=reverse(head,tail);
        head->next=reverseKGroup(tail, k);
        return newHead;
    }
    ListNode* reverse(ListNode* head,ListNode* tail){
        ListNode* pre=nullptr;
        ListNode* cur=head;
        ListNode* nex=nullptr;
        while(head!=tail){
            nex=cur->next;
            cur->next=pre;
            pre=cur;
            cur=nex;
        }
        return pre;
    }
};

删除链表中的重复节点
/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* deleteDuplicates(ListNode* head) {
        // write code here
        if(head==nullptr){
            return nullptr;
        }
        if(head->next&&head->val==head->next->val){
            while(head->next&&head->val==head->next->val)
            {
                head=head->next;
            }
            return deleteDuplicates(head->next);
        }
        head->next=deleteDuplicates(head->next);
        return head;
    }
};
判断一个链表是否为回文结构

使用快慢指针找出中点,reverse后半部分,然后逐个比较

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 the head
     * @return bool布尔型
     */
    bool isPail(ListNode* head) {
        // write code here
       ListNode * fast=head;
        ListNode* slow=head;
        while(fast&&fast->next){
            fast=fast->next->next;
            slow=slow->next;
        }
        if(fast!=nullptr){//如果不为空,说明链表长度为奇数,slow向后走一个
            slow=slow->next;
        }
        slow=reverse(slow);
        fast=head;
        while (slow != nullptr) {
        //然后比较,判断节点值是否相等
        if (fast->val != slow->val)
            return false;
        fast = fast->next;
        slow = slow->next;
    }
    return true;
    }
    ListNode* reverse(ListNode* head){
         ListNode* prev = nullptr;
        while (head != nullptr) {
            ListNode* next = head->next;
            head->next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
};
环形链表的约瑟夫问题
class Solution {
public:
    /**
     * 
     * @param n int整型 
     * @param m int整型 
     * @return int整型
     */
    int ysf(int n, int m) {
        // write code here
        ListNode* head=new ListNode(1);
        ListNode* tail=head;
        for(int i=2;i<=n;i++){
            ListNode* node=new ListNode(i);
            tail->next=node;
            tail=node;
        }
        tail->next=head;
        ListNode* index=head;
        ListNode* pre=tail;
        int count=0;
        while(index->next&&index->next!=index){
            count++;
            ListNode* next=index->next;
            if(count==m){
                pre->next=pre->next->next;
                count=0;
            }
            pre=index;
            index=next;
        }
        return index->val;
    }
};

你可能感兴趣的:(LeetCode刷题笔记)