力扣_初级算法_链表_1~6题

第1题:删除链表中的节点

题目描述:

 举例:

示例 1:

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:

输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

说明:

  • 链表至少包含两个节点。
  • 链表中所有节点的值都是唯一的。
  • 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
  • 不要从你的函数中返回任何结果。

应用背景(自己琢磨想的):这个算法比较简单,只是我用的指针个数没有教材上的多。

简化了一下( 但副作用是没有释放 需要被删除节点的 )

思路:略。

实现:(C++

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}    //结构体的构造函数,C++中有,C中没有
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {      //传入的是指向被删除元素的指针
node->val=node->next->val;        //使得该指针指向节点(非末尾,题目中说的)的数值,变为下一个节点的数值
node->next=node->next->next;       //使得该指针指向的节点的指针域改变方向,去指向往后数第二个节点
}                    //举例: 1->2->3 (要求删除2)。 第一步:1->3->3。 第二步:1->3
};


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第2题:删除链表的倒数第N个节点

题目描述:

给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

举例:

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

应用背景(自己琢磨想的):为什么要删倒着数的?可能是为了加点难度。

删除正着数很容易。这道题就想训练一下我们的思维。

思路:可以使用双指针(快慢指针,一个向前走得快,一个向前走得慢。靠它俩之间的“位移”差来判断位置)。也可以用一般思路,

先遍历有多少个节点。用其节点的总数目减去n,就回到正着数的情况。

实现:(C++)我用的一般思路

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}     //结构体的构造函数,C++中有,C中没有
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int i=0,index;          //index:作为下标
ListNode *p,*q;       //定义两个结构体指针
p=head;
q=head;
while( head )        //遍历一遍链表,看有多少个节点
{
i++;
head=head->next;
}
head=p;
if( n>i||n<=0 ) return 0;   //保证程序的健壮性,防止n乱来
index=i-n;        //顺着数(也就是,正着数的意思)过来的位置的前一位
while( index-1>0 )    //使得q指向被删除节点的前一个节点
{
q=q->next;      //经过这整个循环体后,q最终指向被删除节点的前一个节点
index--;
}
if( index==0 )      //如果被删除的节点是表头(链表首部)
{
head=head->next;
}
else        //如果被删除的节点,不位于链表头
{
p=q->next;
q->next=p->next;
}
return head;    //返回头指针
}
};

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第3题:反转链表

题目描述:反转一个单链表。

举例:

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

应用背景(自己琢磨想的):感觉和数学里面的“对称”、“中心对称”,物理里的“对称性”有共性。

反转链表可以进一步用来判断“回文链表”。也可以进一步延伸到“局部反转”,再进一步扩展到“链表排序”。

思路:巧妙地运用递归函数。(看思路图时,要结合代码来看,清晰一点) PS:思路图纯word文档做,小心酸~~~


实现:(C++)

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}     //结构体的构造函数,C++中有,C中没有
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {     //温馨提示:要注意head 在不同的递归函数里充当的角色
if( head==NULL||head->next==NULL )
return head;
int i;
ListNode *re_head=head;
re_head=reverseList( re_head->next );   //递归在这里,递归的调用点。结合那个思路图来看,清晰一点
head->next->next=head;                     //再次提示:要注意head 在不同函数里充当的角色
head->next=NULL;
return re_head;
}
};

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第4题:合并两个有序链表                      

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

举例:

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
应用背景(自己琢磨想的):把两个学校的考生成绩糅合到一起,并且升序排列。

思路:建立一个哑结点( “节点”和“结点”都可以 ,哑结点就是在链表前面再加一个没有储存信息的结点),然后分别用两个指针( l1和l2 )指向第一个和第二个链表头。

再定义一个指针 pre ,这个指针总是指向,先前移动的指针 l1(或者指针 l2)的前面一位数。

思路图如下:

实现:( 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* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode prehead(-1);        //哑结点,初始值赋为-1,调用的结构体里的构造函数
ListNode *pre=&prehead;
if( l1==NULL )            //如果有一个链表为空,直接返回另一个链表
return l2;
if( l2==NULL )
return l1;
while( l1!=NULL&&l2!=NULL )   //如果 指针l1和l2 中有一指向“空”(即指向NULL)了后,直接跳出
{
if( l1->val <= l2->val )
{
pre->next=l1;
l1=l1->next;
}
else
{
pre->next=l2;
l2=l2->next;
}
pre=pre->next;
}
if( l1==NULL )          //处理最后剩下一根“红线”(我的思路图里的 最后那根 红线 )
pre->next=l2;
else
pre->next=l1;
return prehead.next;
}
};

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第5题:回文链表

题目描述:

请判断一个链表是否为回文链表。

举例:

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true
应用背景(自己琢磨想的):来了来了,“回文链表”是“反转链表”的亲戚。实际应用的东西,
我还没想出来。但和“回文数”、“回文字符串”都有相似之处。
思路:我用了一个vector容器,来装这个链表的每个节点的信息。因为链表的特殊性( 单个指针不能倒着依次访问链表 )。但数组可以,
而我这里就用了vector的一些数组的功能。 当然,我在论坛中看到有些大佬用递归的方法,琢磨很久,还是没看懂。C++悟力尚浅~~~
实现:(C++)

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> v1;          //建立一个vector容器,装int类型的数据
int i;
ListNode *p=head;
while( head )
{
v1.push_back( head->val );    //①新学到一个函数push_back( 变量 ), 每次向容器末尾插入一个元素
head=head->next;
}
for( i=0;i<v1.size()/2;i++)     //原来容器里也可以用size()。 注:i只用循环vector容器所装数据个数的一半即可
{
if( v1[i]!=v1[ v1.size()-1-i ] )    //来来回回比较
return false;
}
return true;
}
};

-----------------------------------------------------------------------------------------------------------

第6题:环形链表
题目描述

给定一个链表,判断链表中是否有环。


为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

举例:


应用背景(自己琢磨想的):感觉用处很广。判断网络信息流通是否有“滞留点”。
感觉以后会有用,现在还没想到深的东西。
思路:使用双指针(一个走得快一点:快指针。一个走得慢一点:慢指针)。一个快一个慢。如果有“环”,那就像在操场的
跑道上,快指针肯定会慢慢地追上慢指针。进而进行区分是否有“环”。

实现:(C++)

/**
* 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!=NULL&&fast->next!=NULL )    //如果快指针能走到“空”(也就是,最终它能指向NULL),说明该链表无“环”
{
fast=fast->next->next;        //快指针每次“走”两步
slow=slow->next;          //慢指针每次“走”一步
if( fast==slow )           //两个指针相遇了,说明有环
return true;
}
return false;
}
};

 






原文地址:https://www.cnblogs.com/Wang-dou-dou/p/13276969.html