leetcode刷题(2):链表

文章目录

    • [1. 两数相加](#1. 两数相加)
      • [1.1 解题思路](#1.1 解题思路)
      • [1. 2 c++ 实现](#1. 2 c++ 实现)
    • [2 删除排序链表中的重复元素 ||](#2 删除排序链表中的重复元素 ||)
      • [2.1 解题思路](#2.1 解题思路)
      • [2.2 c++ 实现](#2.2 c++ 实现)
    • [3 旋转链表](#3 旋转链表)
      • [3.1 解题思路](#3.1 解题思路)
      • [3.2 c++ 实现](#3.2 c++ 实现)
    • [4 剑指 Offer 06: 从尾到头打印链表](#4 剑指 Offer 06: 从尾到头打印链表)
      • [4.1 解题思路](#4.1 解题思路)
      • [4.2 c++ 实现](#4.2 c++ 实现)
    • [5 剑指 Offer 24. 反转链表](#5 剑指 Offer 24. 反转链表)
      • [5.1 解题思路](#5.1 解题思路)
      • [5.2 c++实现](#5.2 c++实现)
    • [21. 合并两个有序链表](#21. 合并两个有序链表)
    • [147. 对链表进行插入排序](#147. 对链表进行插入排序)
    • [114. 二叉树展开为链表](#114. 二叉树展开为链表)

1. 两数相加

  • 题目:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

  • 要求:请你将两个数相加,并以相同形式返回一个表示和的链表

    你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

  • 提示:

    • 每个链表中的节点数在范围 [1, 100] 内
    • 0 <= Node.val <= 9
    • 题目数据保证列表表示的数字不含前导零

1.1 解题思路

要求: 返回一个新链表,存储两个逆序的链表之和,返回的新链表也是逆序排列
思路

  • 从链表的头开始按位加,就可以计算出结果
  • 根据加法原则:对应位置的计算结果为:两数之和对10取余数,同时 两数之和与10相除取整,为向前进位的数字。

1. 2 c++ 实现

  • 解题1:
c 复制代码
class Solution{
public:
    ListNode* addTwoNumber(ListNode* l1,ListNode* l2)
    {
		ListNode* dummy = new ListNode(-1);
		ListNode p = dummy;
		bool carry =false;
		
		while (l1 || l2)
		{
			int sum =0;
			if (l1 != nullptr)
			{
				sum +=l1->val;
				l1 =l1->next;
			}
			
			if (l2 != nullptr)
			{
				sum +=l2->val;
				l2 =l2->next;
			}
			if (carry)
			{
				sum ++;
			}
			
			p->next = new ListNode(sum%10);
			p =p->next;
			if (sum >10)
			{
				carry = true;
			}
			else
			{
				carry = false;
			}
		}
		if (sum >10)
		{
		   p->next = new ListNode(1);
		}
		return dummy->next;
	}
}
  • 改进版
c 复制代码
/**
 * 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* addTwoNumbers(ListNode* l1, ListNode* l2)
   {
   		//1. 创建一个dummy节点
   		ListNode* dummy = new ListNode(-1);
   		ListNode* p = dummy;
   		int t =0;
	   while(l1 || l2 || t)
	   {
	   	 if(l1)
	   	 {
	   	 	t += l1->val;
	   	 	l1 = l1->next;
	   	 }
	   	 if(l2)
	   	 {
	   	 	t += l2->val;
	   	 	l2 = l2->next;
	   	 }
		
		 p->next = new ListNode(t % 10);
		 p = p->next;
		 t = t/10;
	   }
	   return dummy ->next;
   }
};

2 删除排序链表中的重复元素 ||

对应为leetcode 82题,中等难度

题目: 给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表
示例:

提示:

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

2.1 解题思路

  • 链表已排序,重复元素都是连续的
  • 找到两个值相同的连续节点p1,p2,假设值都为x
  • 遍历节点,如果节点p->next值等于x(因为p为dummy节点,所以从p->next开始遍历),则删除该节点:p->next = p->next->next;

2.2 c++ 实现

c 复制代码
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head ==nullptr || head->next ==nullptr) return nullptr;
        ListNode* dummy = new ListNode(-1);
        dummy ->next =head;
        ListNode* p=dummy;

        while (p->next && p->next->next)
        {
              if(p->next->val == p->next->next->val)
              {
                  int x =p->next->val;
                  while (p->next && p->next->val==x)
                  {
                      p->next =p->next->next;
                  }
              }
              else
              {
                  p = p->next;
              }
        }
        return dummy->next;
    }
};

3 旋转链表

对应为leetcode 61题,中等难度
题目给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置
示例:

3.1 解题思路

  • 移动k个位置,计算旋转数据
  • 利用旋转数据,构建链表

参考:LeetCode-轮转数组的三种方法(189)

3.2 c++ 实现

  • 解题1(击败55%)
c 复制代码
class Solution {
public:
    void reverse(vector<int>&nums,int left,int right) 
        {
            while(left < right)
            {
                int tmp = nums[left];
                nums[left] =nums[right];
                nums[right] = tmp;
                left++;
                right--;
            }
        }

    ListNode* rotateRight(ListNode* head, int k) {
        if(head==nullptr) return nullptr;
        
        ListNode* dummy = new ListNode(-1);
        ListNode* p= dummy;
        vector<int> res;
        
        
        while(head)
        {
            res.push_back(head->val);
            head = head->next;
        }

        int len= res.size();

        reverse(res,0,len-1);
        reverse(res,0,k%len-1);
        reverse(res,k%len,len-1);

        for(auto val:res)
        {
            p->next = new ListNode(val);
            p = p->next;
        }
        
        return dummy->next;
    }

    
};
  • 解题2(击败88.54%)

每旋转一次,得到的新数组:

数组中第一个元素,为原来最后一个元素

数组中1-len-1的元素,对应原来0-(len-2)元素,相当于对原来0~len-2元素向右平移1次

c 复制代码
class Solution {
public:
    // void reverse(vector<int>&nums,int left,int right) 
    //     {
    //         while(left < right)
    //         {
    //             int tmp = nums[left];
    //             nums[left] =nums[right];
    //             nums[right] = tmp;
    //             left++;
    //             right--;
    //         }
    //     }
    // 每旋转一次,得到的新数组:数组中第一个元素,为原来最后一个元素
    // 数组中1-len-1的元素,对应原来0~len-2元素,相当于对原来0~len-2元素向右平移1次
    void rotate3(vector<int>& nums,int k) {
        for(int i=0;i<k%nums.size();i++) {
            int temp=nums[nums.size()-1];
            for(int j=nums.size()-2;j>=0;j--) {
                nums[j+1]=nums[j];
            }
            nums[0]=temp;
        }

    }


    ListNode* rotateRight(ListNode* head, int k) {
        if(head==nullptr) return nullptr;

        ListNode* dummy = new ListNode(-1);
        ListNode* p= dummy;
        vector<int> res;
        
        
        while(head)
        {
            res.push_back(head->val);
            head = head->next;
        }

        int len= res.size();

        rotate3(res,k);

        // reverse(res,0,len-1);
        // reverse(res,0,k%len-1);
        // reverse(res,k%len,len-1);

        for(auto val:res)
        {
            p->next = new ListNode(val);
            p = p->next;
        }
        
        return dummy->next;
    }

    
};

4 剑指 Offer 06: 从尾到头打印链表

题目:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 :

c 复制代码
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]

4.1 解题思路

  • 获得链表所有的值
  • 利用reverse反转

4.2 c++ 实现

c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        vector<int> res;

        while(head)
        {
            res.push_back(head->val);
            head=head->next;
        }

        reverse(res.begin(),res.end());

        return res;
    }
};

5 剑指 Offer 24. 反转链表

题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

== 示例==:

c 复制代码
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

5.1 解题思路

5.2 c++实现

c 复制代码
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        vector<int> res;
        ListNode *p= head;
        ListNode *q = head; 
        while(p)
        {
            res.push_back(p->val);
            p=p->next;
        }

        reverse(res.begin(),res.end());
        
        for(int i = 0;i < res.size();i++)
        {    
            q->val = res[i];
            q = q->next; 
        }
        return head;
    }
};

21. 合并两个有序链表

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

== 示例==:

解题思路

  • 新链表是通过拼接给定的两个链表的所有节点组成的,所以不能单纯用值来构建链表,而是需要基于两个链表的节点构建
  • 如果两个链表都非空,比较两个链表的值,将值小的节点,赋给新的节点
  • 随着遍历,其中一个链表为空,另一个为非空,此时将非空的链表节点,分配给新链表

c++ 实现

c 复制代码
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        // ListNode* dummy = new ListNode();
        ListNode dummy(-1);
        ListNode* p = &dummy;

        while(l1&&l2)
        {
            if(l1->val <= l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;

        }

        while(l1)
        {
            p->next = l1;
            l1 = l1 ->next;
            p = p->next;
        }

        while(l2)
        {
            p->next = l2;
            l2 =l2->next;
            p = p->next;
        }

        return dummy.next;
    }
};

147. 对链表进行插入排序

114. 二叉树展开为链表

题目: 给你二叉树的根结点 root ,请你将它展开为一个单链表

展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。

展开后的单链表应该与二叉树 先序遍历 顺序相同。

== 示例==:

相关推荐
_平凡之路_14 分钟前
解决ubuntu22.04 gnome-terminal 无法启动的问题
linux·运维·python
凯子坚持 c16 分钟前
0基础带你入门Linux之使用
linux·运维·服务器
曳渔22 分钟前
Java-数据结构-二叉树-习题(三)  ̄へ ̄
java·开发语言·数据结构·算法·链表
shark-chili33 分钟前
数据结构与算法-Trie树添加与搜索
java·数据结构·算法·leetcode
EterNity_TiMe_34 分钟前
【Linux基础IO】深入Linux文件描述符与重定向:解锁高效IO操作的秘密
linux·运维·服务器·学习·性能优化·学习方法
python-码博士34 分钟前
Rosetta 一:手把手教你用Linux安装Rosetta(全网最简洁)
linux·运维·服务器
神秘的土鸡1 小时前
Linux中Docker容器构建MariaDB数据库教程
linux·运维·服务器·数据库·docker·mariadb
路溪非溪2 小时前
Linux内核启动流程
linux·运维·服务器
小丁爱养花2 小时前
记忆化搜索专题——算法简介&力扣实战应用
java·开发语言·算法·leetcode·深度优先
anddddoooo2 小时前
vulnhub(11):derpnstink(hydra爆破用户名和密码、验证的文件上传)
linux·运维·服务器·安全·web安全·网络安全