【LeetCode】链表相关问题总结

链表相关问题总结

链表相关辅助函数

链表结构

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(NULL) {}
    
};

数组创建链表

ListNode* creat(int num[], int n)
{
    if (n == 0)return NULL;
    ListNode* head = new ListNode( num[0]);
    ListNode* ret = head;
    for (int i = 1;i < n;i++)
    {
        head->next = new ListNode(num[i]);
        head = head->next;
    }
    return ret;
}

向量创建链表

ListNode* creat(vector<int> num)
{
    if (num.size() == 0)return NULL;
    ListNode* head = new ListNode(num[0]);
    ListNode* ret = head;
    for (int i = 1;i < num.size();i++)
    {
        head->next = new ListNode(num[i]);
        head = head->next;
    }
    return ret;
}

链表末尾插入元素

ListNode* insert(ListNode* head,int num)
{
    if (head == NULL)
        return new ListNode(num);
     ListNode* tmp = head;
     while (tmp->next != NULL)
     {
         tmp = tmp->next;
     }
     tmp->next = new ListNode(num);
     return head;
}

删除和打印

void deletelink(ListNode* head)
{
    ListNode* tmp;
    while (head!= NULL)
    {
        tmp = head->next;
        delete head;
        head = tmp;
    }
}
void printlist(ListNode* head)
{
    while (head != NULL)
    {
        cout << head->val << "->";
        head = head->next;
    }
    cout << "NULL"<< endl;
}

链表节点间穿针引线

206. 反转链表

题目描述

在这里插入图片描述

方法1 迭代

    ListNode* reverseList1(ListNode* head) {
        if (head == NULL)return head;
        ListNode* pre = head;
        ListNode* tmp = head->next; //要反转的链表
        ListNode* next; //缓存下一个
        while (tmp != NULL)
        {
            next = tmp->next;//缓存
            tmp->next = pre;//反转
            pre = tmp;//移动
            tmp = next;//移动
            
        }
        head->next = NULL;//头节点
        return pre;
    }

方法2 递归

1->2->3->4
递归返回 4->3->NULL
对于节点2
2->next=3
2->next->next=2
变成
4->3->2
2->next=NULL
变成
4->3->2->NULL
返回头节点4 完成反转

    ListNode* preverse(ListNode* node)
    {
        if (node->next == NULL)
        {
            return node;
        }
        else
        {
            ListNode* tmp=preverse(node->next);//返回已经反转过的链表的头节点
            node->next->next = node;//当前节点
            node->next = NULL;
            return tmp;
        }   
    }
    ListNode* reverseList(ListNode* head) {
        if (head->next == NULL||head==NULL)
        {
            return head;
        }
        else
        {
            ListNode* tmp = preverse(head->next);
            head->next->next = head;
            head->next = NULL;
            return tmp;
        }
    }

92. 反转链表 II

题目描述

在这里插入图片描述

方法1 缓存相关节点

    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if (head == NULL || head->next == NULL||m==n)return head;
        ListNode* tmp;
        ListNode* pre=head;
        ListNode* next;
        ListNode* res1 = new ListNode(-1);// 重点 打造虚拟头结点
        ListNode* res2 = res1;//缓存头结点位置
        res1->next = head;
       
        int count = 0;
        while (count < m-1) {
            res1 = res1->next;//开始反转的前一个元素位置缓存
            count++;
        }
        pre = res1->next;
        tmp = pre->next;
        while (count < n-1)//找到终止位置 
        {
            next = tmp->next;//依次反转节点
            tmp->next = pre;
            pre = tmp;
            tmp = next;
            count++;
        }
        res1->next->next = tmp;//反转的起始元素连接末尾
        res1->next = pre;//链表的起始连接反转末尾
        ListNode* ret = res2->next;
        res2->next = NULL;
        delete res2;//释放内存
        return ret;
    }

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

题目描述

在这里插入图片描述

方法1 保留第一个重复元素

    ListNode* deleteDuplicates1(ListNode* head) {
        if (head == NULL || head->next == NULL)
        {
            return head;
        }
        ListNode* pre = head;//看前一个元素
        ListNode* tmp = head->next;
        //ListNode* next = NULL;
        while (tmp!=NULL)
        {
            while (tmp!=NULL&&tmp->val == pre->val)//出现重复
            {
                pre->next = tmp->next;//删除第后面出现的元素
                delete tmp;
                tmp = pre->next;
            }
            pre = tmp;//向后移动
            if (tmp != NULL)
            {
                tmp = tmp->next;
            }
        }
        return head;
    }

方法2 保留第一个重复元素优化

    ListNode* deleteDuplicates2(ListNode* head) {
        ListNode* tmp = head;//看后一个元素
        while (tmp != NULL && tmp->next != NULL)
        {
            if (tmp->val == tmp->next->val)
            {
                tmp->next = tmp->next->next;
            }
            tmp = tmp->next;
        }
        return head;
    }

86. 分隔链表

题目描述

在这里插入图片描述

方法1 根据大小划分成两个子链表再合并

    ListNode* partition(ListNode* head, int x) {
        ListNode* lesshead=new ListNode(-1);
        ListNode* largehead= new ListNode(-1);
        ListNode* lres = lesshead;//值小的数
        ListNode* larres = largehead;//值大的数
        while (head != NULL)
        {
            if (head->val < x)
            {
                lesshead->next = head;
                head = head->next;
                lesshead = lesshead->next;
            }
            else
            {
                largehead->next = head;
                head = head->next;
                largehead = largehead->next;
            }
        }
        largehead->next = NULL;
        lesshead->next = larres->next;
        head = lres->next;
        delete lres;
        delete larres;
        return head;
    }

328. 奇偶链表

题目描述

在这里插入图片描述

方法1 分成两个子链表再合并

    ListNode* oddEvenList(ListNode* head) {
        ListNode* lesshead = new ListNode(-1);
        ListNode* largehead = new ListNode(-1);
        ListNode* lres = lesshead;
        ListNode* larres = largehead;
        while (head != NULL)
        {
            
                lesshead->next = head;//奇数
                head = head->next;
                lesshead = lesshead->next;
            
            if(head!=NULL)
            {
                largehead->next = head;//偶数
                head = head->next;
                largehead = largehead->next;
            }
        }
        largehead->next = NULL;
        lesshead->next = larres->next;
        head = lres->next;
        delete lres;
        delete larres;
        return head;
    }

2. 两数相加

题目描述

在这里插入图片描述

方法1 转化成整数在转化成链表(数字太大会溢出)

    ListNode* addTwoNumbers1(ListNode* l1, ListNode* l2) {
        long long a1 = 0;
        long long a2 = 0;
        long long count = 1;
        while (l1 != NULL)
        {
            a1 = l1->val * count + a1;
            l1 = l1->next;
            count = count * 10;
        }
        count = 1;
        while (l2 != NULL)
        {
            a2 = count * l2->val + a2;
            l2 = l2->next;
            count = count * 10;
        }
        int a3 = a1 + a2;
        vector<long long> ret;
        if (a3 == 0)
        {
            ret.push_back(0);
        }
        while (a3 != 0)
        {
            ret.push_back(a3 % 10);
            a3 = a3 / 10;
        }
        ListNode* rett = creat(ret);
        return rett;
    }

方法2 从头到尾依次按位相加

    ListNode* addTwoNumbers2(ListNode* l1, ListNode* l2) {
        ListNode* head1 = l1;
        ListNode* head2 = l2;
        bool addflag = false;
        bool l1flag = false;
        bool r1flag = false;
        int value1 = 0;
        int value2 = 0;
        ListNode* rettmp = new ListNode(-1);
        ListNode* ret = rettmp;
        //rettmp = rettmp->next;
        while (head1 != NULL || head2 != NULL)
        {
          //  addflag = false;
            if (head1 == NULL)//l1加完了
            {
                l1flag == true;
                value1 = 0;
                value2 = head2->val;
                head2 = head2->next;
            }
            else if (head2 == NULL)//l2加完了
            {
                r1flag == true;
                value1 = head1->val;
                head1 = head1->next;
                value2 = 0;
            }
            else
            {
                value1=head1->val;
                head1 = head1->next;
                value2 = head2->val;
                head2 = head2->next;
            }
            int tmp = value1 + value2+int(addflag);//进位
            if (tmp >= 10)
            {
                addflag = true;
                tmp = tmp % 10;
            }
            else
            {
                addflag = false;
            }
            rettmp->next = new ListNode(tmp);//注意这里不是rettmp=new node 否则会成为NULL转为listnode
            rettmp = rettmp->next;  
            
        }
        if (addflag == true)//最后是否有进位
        {
            rettmp = new ListNode(1);
        }
        ListNode* res = ret->next;
        delete ret;
        return res;
    }

445. 两数相加 II

题目描述

在这里插入图片描述

方法1 使用栈逆序再转化成链表

    ListNode* addTwoNumbers3(ListNode* l1, ListNode* l2) {
        ListNode* p = l1;
        ListNode* q = l2;
        stack<int> pstack;
        stack<int> qstack;
        stack<int> kstack;//结果储存位置
        ListNode* ret = new ListNode(-1);
        ListNode* rettmp = ret;
        while (p != NULL)
        {
            pstack.push(p->val);//入栈
            p = p->next;
        }
        while (q != NULL)
        {
            qstack.push(q->val);//入栈
            q = q->next;
        }
        int value1 = 0;
        int value2 = 0;
        int tmp;
        bool addflag = false;
        while (!pstack.empty() || !qstack.empty())
        {
            value1 = 0;
            value2 = 0;
            if (!pstack.empty())
            {
                value1 = pstack.top();
                pstack.pop();
            }
            if (!qstack.empty())
            {
                value2 = qstack.top();
                qstack.pop();
            }
            tmp = value1 + value2 + int(addflag);
            addflag = tmp >= 10 ? true : false;
            tmp = tmp % 10;
            kstack.push(tmp);//储存结果
        }
        if (addflag == true)
        {
            kstack.push(1);
        }
        while (!kstack.empty())//转化成链表
        {
            ret->next = new ListNode(kstack.top());
            kstack.pop();
            ret = ret->next;
        }
        ListNode* res = rettmp->next;
        delete rettmp;
        return res;
    }

方法2 使用栈优化

    ListNode* addTwoNumbers4(ListNode* l1, ListNode* l2) {
        ListNode* p = l1;
        ListNode* q = l2;
        stack<int> pstack;
        stack<int> qstack;
        stack<int> kstack;
        ListNode* ret = NULL;
       // ListNode* rettmp = ret;
        while (p != NULL)
        {
            pstack.push(p->val);
            p = p->next;
        }
        while (q != NULL)
        {
            qstack.push(q->val);
            q = q->next;
        }
        int value1 = 0;
        int value2 = 0;
        int tmp;
        bool addflag = false;
        while (!pstack.empty() || !qstack.empty()||addflag)//addflag 避免对于最后一位进行冗余代码  
        {
            value1 = 0;
            value2 = 0;
            if (!pstack.empty())
            {
                value1 = pstack.top();
                pstack.pop();
            }
            if (!qstack.empty())
            {
                value2 = qstack.top();
                qstack.pop();
            }
            tmp = value1 + value2 + int(addflag);
            addflag = tmp/10;
            tmp = tmp % 10;
            ListNode* res = new ListNode(tmp);
            res->next = ret;//链表增加节点 之后把新节点的next指向之前的链表
            ret = res;
        }
        return ret;
    }

方法3 链表对齐后使用双指针

    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int count = 0, temp;
        ListNode* head, * last;
        for (head = l1; head; head = head->next)
            count++;
        for (head = l2; head; head = head->next)
            count--;
        if (count < 0)                       //计算两链表长度,将l1指向长链,l2指向短链,将l2的值加到l1中
            swap(l1, l2);
        last = head = new ListNode(0);      //在链首加一个值为0的节点作为初始的last节点,如果最终该节点值仍为0则删除该节点
        head->next = l1;
        for (int i = abs(count); i != 0; i--) {  //将两链数位对齐
            if (l1->val != 9)
                last = l1;
            l1 = l1->next;
        }
        while (l1) {
            temp = l1->val + l2->val;
            if (temp > 9) {                   //如果发生进位,则更新last到l1之间所有数位的值
                temp -= 10;                 //进位后当前数位最大值为8,故将last指针指向当前数位
                last->val += 1;
                last = last->next;
                while (last != l1) {
                    last->val = 0;
                    last = last->next;
                }
            }
            else if (temp != 9)
                last = l1;
            l1->val = temp;
            l1 = l1->next;
            l2 = l2->next;
        }
        return head->val == 1 ? head : head->next;
    }

设立虚拟头节点

203. 移除链表元素

题目描述

在这里插入图片描述

方法1 设立虚拟头节点

    ListNode* removeElements1(ListNode* head, int val) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        while (cur->next != NULL)
        {
            if (cur->next->val == val)
            {
                ListNode* delnode = cur->next;
                cur->next = delnode->next;
                delete delnode;
            }
            else//用else
            {
                cur = cur->next;
            }
        }
        ListNode* ret = dummyhead->next;
        delete dummyhead;
        return ret;
    }

方法2 对头节点单独处理

    ListNode* removeElements(ListNode* head, int val) {
        while (head != NULL && head->val == val)
        {
            ListNode* delnode = head;
            head = delnode->next;
            delete delnode;
        }
        if (head == NULL)return NULL;
        ListNode* cur = head;
        while (cur->next != NULL)
        {
            if (cur->next->val == val)
            {
                ListNode* delnode = cur->next;
                cur->next = delnode->next;
                delete delnode;
            }
            else//用else
            {
                cur = cur->next;
            }
        }
        return head;
    }

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

题目描述

在这里插入图片描述

方法1 使用flag判断当前节点是否是最后一个重复元素

    ListNode* deleteDuplicates3(ListNode* head) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        ListNode* next = cur->next;
        int val;
        while (cur->next != NULL)
        {
            //if(cur->next->val==val)
            val = cur->next->val;
            next = next->next;
            bool delflag = false;
            while (next != NULL && next->val == val)//如果有重复 删除第二个节点
            {
                ListNode* delnode = next;//删除第二个节点
                cur->next->next = next->next;//前面指针连接后面指针
                next = next->next;//next后移
                delete delnode;
                delflag = true;
            }
            if (delflag == true)//删除当前节点
            {
                ListNode* delnode = cur->next;
                cur->next = delnode->next;
                delete delnode;
                next = cur->next;//next指向下一个
            }
            else//不需要删除节点
            {
                cur = cur->next;//直接后移
                next = cur->next;//直接后移
            }
        }
        ListNode* res = dummyhead->next;
        delete dummyhead;
        return res;
    }

复杂的穿针引线

24. 两两交换链表中的节点

题目描述

在这里插入图片描述

方法1 缓存多个节点

    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead->next = head;
        ListNode* pre = dummyhead;
        while (pre->next != NULL && pre->next->next != NULL)
        {
            ListNode* node1 = pre->next;
            ListNode* node2 = node1->next;
            node1->next = node2->next;
            node2->next = node1;
            pre->next = node2;
            pre = node1;
        }
        ListNode* ret = dummyhead->next;
        delete dummyhead;
        return ret;
    }

25. K 个一组翻转链表

题目描述

在这里插入图片描述

方法1

    ListNode* reverse(ListNode* head)//子函数
    {
        //ListNode* dummyhead = new ListNode(-1);
        //dummyhead->next = head;
        ListNode* pre = head;
        ListNode* cur = pre->next;
        ListNode* next; 
        while (cur != NULL)
        {
            next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        head->next = NULL;
        return pre;
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead->next = head;
        ListNode* pre = dummyhead;
        ListNode* cut = pre;
        int count = 0;
        while (pre->next != NULL)
        {
            count = 0;
            ListNode* tmpreverst;// = pre;
            ListNode* tmphead = pre->next;
            cut = pre;
            while (cut->next!=NULL&&count < k)
            {
                cut = cut->next;
                count++;
            }
            if (count != k)//处理结尾不够k个
            {
                break;
            }
            tmpreverst = cut->next;//提前缓存
            cut->next = NULL;//next设置为NULL
            pre->next = reverse(tmphead);//反转链表
            tmphead->next = tmpreverst;
            pre = tmphead;
        }
        ListNode* ret = dummyhead->next;
        delete dummyhead;
        return ret;
    }

147. 对链表进行插入排序

题目描述

在这里插入图片描述

方法1

    ListNode* insertionSortList(ListNode* head) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead->next = head;
        ListNode* pre = dummyhead->next;
        ListNode* cur;// = pre->next;
        bool del = false;
        while (pre->next != NULL)
        {
            cur = pre->next;
            while (cur!=NULL&&pre->val < cur->val)//找到删除的节点
            {
                pre = cur;
                cur = cur->next;
            }
            if (cur == NULL)
                break;
            pre->next = cur->next;//移除之前节点
           // pre = dummyhead;
            ListNode* tpre = dummyhead;//从头开始遍历找到插入的位置
            while (tpre->next->val < cur->val)
            {
                tpre = tpre->next;
            }
            ListNode* tmp = tpre->next;
            tpre->next = cur;
            cur->next = tmp;
            //pre=
        }
        ListNode* ret = dummyhead->next;
        delete dummyhead;
        return ret;
    }

148. 排序链表(还没做)

不仅仅是穿针引线

237. 删除链表中的节点

题目描述

在这里插入图片描述

方法1 没有前驱节点 改变链表中的值

void deleteNode(ListNode* node)
    {
    	ListNode* del=node->next;
        node->val=del->val;
        ListNode* next=del->next;
        node->next=next;
        delete del;
    }
 

链表与双指针

19. 删除链表的倒数第N个节点

题目描述

在这里插入图片描述

方法1 遍历链表统计长度

比较简单

方法2 双指针

    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead->next = head;
        ListNode* pre = dummyhead;
        ListNode* cur=dummyhead;
        for (int i = 0; i < n; i++)
        {
            cur = cur->next;
        }
        while (cur->next != NULL)//结束条件 后面的指针为空
        {
            pre = pre->next;
            cur = cur->next;
        }
        ListNode* del = pre->next;
        pre->next = del->next;
        delete del;
        del = dummyhead->next;
        delete dummyhead;
        return del;
    }

61. 旋转链表

题目描述

在这里插入图片描述

方法1

ListNode* rotateRight(ListNode* head, int k) {
	int len = 0;
        ListNode* pre = head;
        while (pre != NULL)
        {
            pre = pre->next;
            len++;
        }
        k = k % len;//找到倒数第k个元素 倒数第k个yuan's元素变成头节点
        pre = head;
        for (int i = 0; i < k; i++)
        {
            if (pre->next != NULL)
            {
                pre = pre->next;
            }
            else
            {
                pre = head;
            }
        }
        ListNode* del = head;
        if (pre == head)
        {
            return head;
        }
        while (pre->next != NULL)
        {
            pre = pre->next;
            del = del->next;
        }
        ListNode* newhead = del->next;
        pre->next = head;
        del->next = NULL;
        return newhead;
    }

143. 重排链表

题目描述

在这里插入图片描述

方法1 使用快慢指针找到中间节点并进行归并

    void reorderList(ListNode* head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (slow->next != NULL&&slow->next->next!=NULL)
        {
            fast = fast->next;
            slow = slow->next->next;
        }//找到中间节点
        ListNode* newhead = fast->next;
        fast->next = NULL;
        newhead = reverseNode(newhead);
        ListNode* head1 = head;
        ListNode* head2 = newhead;
        ListNode* ret = new ListNode(-1);
        ListNode* re = ret;
        while (head1 != 0)
        {
            ret->next = head1;
            head1 = head1->next;
            ret = ret->next;
            if (head2 != NULL)
            {
                ret->next = head2;
                head2 = head2->next;
                ret = ret->next;
            }
        }
        delete re;
        //return NULL;
        int k = 8;
    }

234. 回文链表

题目描述

在这里插入图片描述

方法1 快慢指针找到中间的节点

    bool isPalindrome(ListNode* head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (slow->next != NULL && slow->next->next != NULL)
        {
            fast = fast->next;
            slow = slow->next->next;
        }
        ListNode* newhead = fast->next;
        fast->next = NULL;
        newhead = reverseNode(newhead);//逆序其中一个链表 
        ListNode* head1 = head;
        ListNode* head2 = newhead;
        while (head1 != NULL)//依次对比
        {
            if (head1->val != head2->val) { return false; }
            head1 = head1->next;
            head2 = head2->next;
            if (head2 == NULL)
            {
                break;
            }
        }
        return true;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值