要求:输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
输入:{1,3,5},{2,4,6}
返回值:{1,2,3,4,5,6}
1.定义一个新的链表,使用新的链表进行重新指向。
2. 分三种情况讨论:第一种情况:链表1为空,链表2不为空;第二种情况:链表1不为空,链表2为空;第三种情况:链表1和链表2都为空或者都不为空的情况。
3. 在第三种情况中,要考虑到比较链表中的元素时,链表1中的元素遍历完还是链表2中的数据先遍历完成。
4. 两个核心是指针的指向问题和指针的移动问题。
具体代码如下:
struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2) {
struct ListNode* cur1 = pHead1; //定义链表1当前一个结点
struct ListNode* cur2 = pHead2; //定义链表2当前一个结点
//只有在头插或者尾插的时候才需要定义两个结点
struct ListNode *newNode = (struct ListNode *)malloc(sizeof(struct ListNode)); //增加一个新的结点
newNode->next = NULL; //新结点指向NULL
struct ListNode *newNode1 = newNode; //定义一个指针指向该头结点
// struct ListNode *newNode1 = (struct ListNode *)malloc(sizeof(struct ListNode)); //增加一个新的结点
struct ListNode *newNode1 = newNode;
if(cur1 == NULL && cur2 != NULL){ //第一种情况:链表1为空,链表2不为空
newNode1->next = cur2;
}else if (cur2 == NULL && cur1 != NULL) { //第二种情况:链表1不为空,链表2为空
newNode1->next = cur1;
}else { //第三种情况:链表1和链表2都为空或者都不为空
while (cur1 != NULL ){
if (cur1->val <= cur2->val) { //依次判断元素大小
newNode->next = cur1;
newNode = newNode->next; //移动指针
cur1 = cur1->next; //移动指针
}else { //这个里面的链表2不能是空 1,16,19和16,16,16的情况
newNode->next = cur2; //指向链表2的元素
newNode = newNode->next; //移动指针
cur2 = cur2->next;
if(cur2 == NULL){
break; //1还没有遍历完,但是2已经完了,直接结束整个循环
}
}
}
while (cur1!= NULL){ //代表链表1还有剩余
newNode->next = cur1; //指向链表1的剩余元素
newNode = newNode->next; //移动指针
cur1 = cur1->next; //移动指针
}
while (cur2!= NULL){ //代表链表2还有剩余
newNode->next = cur2; //指向链表2的剩余元素
newNode = newNode->next; //移动指针
cur2 = cur2->next; //移动指针
}
}
return newNode1->next;
}
优化上面代码:
struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2) {
struct ListNode* cur1 = pHead1; //定义当前一个结点
//定义链表2的前一个结点和当前结点
// struct ListNode *pre2 = NULL; //定义前一个结点
struct ListNode* cur2 = pHead2; //定义当前一个结点
//只有在头插或者尾插的时候才需要定义两个结点
struct ListNode *newNode = (struct ListNode *)malloc(sizeof(struct ListNode)); //增加一个新的结点
newNode->next = NULL;
struct ListNode *newNode1 = newNode;
if(cur1 == NULL){ //这里包含了两个链表都为NULL的情况
newNode1->next = cur2;
}else if (cur2 == NULL) { //这里包含了两个链表都为NULL的情况
newNode1->next = cur1;
}else { //都不为空的情况
while (cur1 != NULL && cur2 != NULL){
if (cur1->val <= cur2->val) { //判断第一个元素, 1链表的第一个元素小
newNode->next = cur1;
newNode = newNode->next; //移动结点
cur1 = cur1->next;
}else { //这个里面的链表2不能是空 1,16,19和16,16,16的情况
newNode->next = cur2; //指向链表2的第一个元素
newNode = newNode->next; //移动结点
cur2 = cur2->next;
}
}
if (cur1!= NULL) { //不再需要用while进行遍历了,直接指向就可以,不用管后面有多少个元素 ,因为1和2的链表还没有断
newNode->next = cur1; //指向链表1的指针,这里不管链表1还有几个元素
}
if (cur2!= NULL) {
newNode->next = cur2; //指向链表2指针,这里不管链表2还有几个元素
}
}
return newNode1->next;
}
struct ListNode *newNode = (struct ListNode *)malloc(sizeof(struct ListNode)); //申请一个新的结点
newNode->next = NULL; //新结点指向NULL
struct ListNode *newNode1 = newNode; //定义一个指针指向该头结点
newNode->next = cur1; //指针指向
newNode = newNode->next; //移动指针
要求:给定一个链表,请判断该链表是否为回文结构。 回文是指该字符串正序逆序完全一致。
输入:{1,2,2,1}
返回值:true
说明:1->2->2->1
1.遍历链表,求出链表的长度。
2. 因为回文链表是对称的,所以要找到链表对称的位置。再遍历一遍链表,找到链表对称的位置,并记录下对称位置的指针,如果是4(偶数)个元素,就记录3(偶数 / 2的下一个位置)的指针位置,如果是7(奇数)个元素,就记录4(奇数 / 2的下一个位置)。
3. 反转对称位置的指针后面的链表,然后进行依次比较,如果都相同返回true,有一个不相同,就返回false。
具体代码如下:
#include
#include
bool isPail(struct ListNode* head) {
int n = 0; //链表总长度
int n1 = 0; //链表指针位置
struct ListNode* cur = head; //定义当前指针
struct ListNode* double_p ; //定义双指针(对称位置的指针)
struct ListNode* double_p_pre ; //定义双指针的前一个指针
struct ListNode* double_p_next; //定义双指针的后一个指针
//链表不能用数组的方法,因为如果把链表的值,存放到数组中还要去考虑是否为奇数,是否为偶数
//遍历链表,计算出链表长度
while (cur!=NULL ) {
n++;
cur = cur->next;
}
cur = head; //复原头指针
if (n==1) {
return true;
}
while (cur!=NULL) { //再遍历一遍,找到n/2的指针
n1++; //就是要从1开始进行
if( n1 == n/2){ //找到双指针的位置在哪
double_p = cur->next; //记录位置,这里是n/2的后一个结点
cur->next = NULL; //前面链表的指向变成空,这时候,链表就断掉了
break;
}
cur = cur->next; //指针后移
}
cur = head; //复原头指针
//遍历剩下的链表
while(double_p != NULL){ //判断当前指针不为NULL
double_p_next = double_p->next; //移动指针 (反转链表需要三次指针的移动,一次指针方向的指向,这是双指针迭代)
double_p->next = double_p_pre; //指针指向
double_p_pre = double_p; //移动前一个指针
double_p = double_p_next; //移动指针
}
while (cur) { //遍历进行比较,这里以前一个链表为判断条件,后面链表的长度比前面的长(多一个对称地方的元素,奇元素的时候),要么就是相等,可以用这个作为条件
if ( cur->val != double_p_pre->val) {
return false;
}
cur = cur->next; //指针移动到下一个位置
double_p_pre = double_p_pre->next; //指针移动到下一个位置
}
return true;
}
bool isPail(struct ListNode* head) {
if(head==NULL) return true;
int list[100000]={0};
int num=0;
struct ListNode* p = head;
while(p!=NULL) {
list[num++] = p->val;
p=p->next;
}
for(int i=0; i<num/2; i++) {
if(list[i] != list[num-1-i]) return false;
}
return true;
}
快慢指针查找链表中点:这种方法利用了两个指针以不同的速度遍历链表,最终当快指针到达链表末尾时,慢指针会正好处于链表中点位置。(可以用这种方法查找链表中点位置)
1.初始化两个指针,一个称为慢指针(slow),一个称为快指针(fast)。初始时,它们都指向链表的头节点。
2.使用循环,每次循环中慢指针向后移动一步,而快指针向后移动两步。这样,快指针的移动速度是慢指针的两倍。
3.检查快指针是否到达链表末尾(即快指针的下一个节点为空,或者快指针本身为空)。如果是这样,循环结束,慢指针所指的节点就是链表的中点。
这种方法的关键在于,当链表的节点数为奇数时,快指针会正好到达末尾节点,而慢指针会停在中点节点上。当节点数为偶数时,快指针会到达倒数第二个节点,慢指针会停在中间的两个节点的第一个。
struct ListNode* findMiddle(struct ListNode* head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
要求:删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次。
输入:{1,1,2}
返回值:{1,2}
输入:{1,1,2,3,4,4,4,6,7,7,7,9,9}
返回值:{1,2,3,4,6,7,9}
#include
#include
struct ListNode* deleteDuplicates(struct ListNode* head)
{
//删除链表中的重复元素,链表中元素从小到大有序
struct ListNode* cur = head; //定义一个指针,指向head
struct ListNode* next_1 = head->next; //头结点下一个结点
if (cur->next == NULL || cur == NULL) { //一个元素,或者没有元素
return cur;
}
while(next_1!=NULL){ //两个及以上的元素
if (cur->val == next_1->val){
cur->next = next_1->next; //当前结点指向下一个结点
next_1 = next_1->next; //移动下一个结点
}else{
cur = cur->next; //移动当前的指针
next_1 = next_1->next; //移动后一个指针
}
}
return head;
}