力扣单链表经典问题

遇到的错误都写在前一篇了,链表主要就是不要空指针->next就好

第一题

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

刚开始接触这种题不会写,直接看答案了

方法一

使用栈解决,不过没想过借助别的东西,也没思考过这个,贴一下代码当作学习吧

public ListNode reverseList(ListNode head) {
    Stack<ListNode> stack = new Stack<>();
    //把链表节点全部摘掉放到栈中
    while (head != null) {
        stack.push(head);
        head = head.next;
    }
    if (stack.isEmpty())
        return null;
    ListNode node = stack.pop();
    ListNode dummy = node;
    //栈中的结点全部出栈,然后重新连成一个新的链表
    while (!stack.isEmpty()) {
        ListNode tempNode = stack.pop();
        node.next = tempNode;
        node = node.next;
    }
    //最后一个结点就是反转前的头结点,一定要让他的next
    //等于空,否则会构成环
    node.next = null;
    return dummy;
}

方法二

双链表求解

这个方法和迭代差不多,迭代是我看了答案后自己写的,等会贴一起

方法三

递归解决

我对递归太不熟练了,以前看的第一个递归都看了半天,这个也是看了半天看不懂,第二天再看评论区里别人的解析终于看懂了,自己也试着自主写了一遍

/**
 * 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) {}
 * };
 */
//   if(head==NULL||head->next==NULL){   //这是迭代
//            return head;               //head是头一个  pre是当前 nex是下一个
//        }                              //当前p指向头一个h之后  头一个h找不到当前p,就直接赋值h变成当前p
//        ListNode *pre=head->next; //当前p找不到下一个n,就直接赋值p变下一个n,然后先用n找到下一个n记录下来
//        ListNode *nex=head->next;
//        head->next=NULL;
//        while(nex!=NULL){
//             nex=nex->next;
//             pre->next=head;
//             head=pre;
//             pre=nex;
//         }
//         return head;
class Solution {
public:
    ListNode* reverseList(ListNode* head) { //比如1 2 3 4 5的链表 
       if(head==NULL||head->next==NULL){        //一直往后,找到最后一个结点5,直接返回
           return head;
       }
       ListNode *newList=reverseList(head->next); //最后一个结点5不做操作直接返回,那么先在倒数第二个结点4进行操作,此时head=4
       head->next->next=head;   //4的下一个是5,5指向4
       head->next=NULL;         //4原本指向5.另它指向空
       return newList;
    }
};

题目二

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

/**
 * 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* removeElements(ListNode* head, int val) {
        ListNode *newhead=head;
        while(head!=NULL&&head->val==val){   //找到第一个与val不一样的结点
            newhead=newhead->next;
            head->next=NULL;
            head=newhead;
        }
        if(newhead==NULL){  //如果本来为空或者链表全被删了,返回head或者newhead都行,都指向空
            return head;
        }                   //如果有新的链表,head是新链表的头,等会拿来输出,不要动了
        ListNode *donull=newhead;   //创建一个指针用来遇到下一个是要删除的结点的时候,让它指向下下个结点
        newhead=newhead->next;      //newhead不是空  值也不是val,直接往后走一步
        while(newhead!=NULL){   //拿newhead遍历,遇到要删的用donull操作,donull是正确链表的位置
            if(newhead->val==val){
                newhead=newhead->next; //遇到要删的结点newhead直接往后走
                donull->next=newhead;  //donull进行操作,因为donull指向要删的结点,让它指向要删的下一个就好
            }
            else{
                newhead=newhead->next;//如果不用操作,直接往前走
                donull=donull->next;     //这个结点不要删,也就是要保留,donull往后走
            }
}//这些代码没有让要删的结点指向空,而是让要删的上一个结点指向要删的下一个结点,要删的结点仍指向要删的下一个结点
        return head;
    }
};

这道题是自己自主写的,写的比较多,这道题主要还是指针判断问题,确定好一些特殊情况,不要访问空指针

题目三

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

/**
 * 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* oddEvenList(ListNode* head) {
        if(head==NULL||head->next==NULL||head->next->next==NULL){
            return head;
        }
        ListNode *odd=head;     //单数链表指向头
        ListNode *oddnn=head;   //用oddnn遍历链表找出奇数结点
        head=head->next;
        ListNode *eve=head;     //偶数链表的头eve
        ListNode *evenn=head;    //用evenn遍历链表找出偶数结点
        head=head->next;
        for(;head!=NULL;){
            oddnn->next=head;
            oddnn=head;
            head=head->next;
            if(head==NULL){
                evenn->next=NULL;
                oddnn->next=eve;
                return odd;
            }
            else{
                evenn->next=head;
                evenn=head;
                head=head->next;
            }
        }
        oddnn->next=eve;
        return odd;
    }
};

自己思考了一下就按照自己思路写了,结果一个=写成==让我检查半天,还是问人别人帮我看出来的,检查的时候一直画图感觉自己思路对结果错在这。

题目四

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

/**
 * 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* reverlist(ListNode *headnn){       //反转函数代码
        if(headnn==NULL||headnn->next==NULL){        
        return headnn;
        }
        ListNode *newList=reverlist(headnn->next); 
        headnn->next->next=headnn;   
        headnn->next=NULL;         
        return newList;
    }
    bool isPalindrome(ListNode* head) {     //题目函数
        if(head==NULL||head->next==NULL){
            return true;
        }
        ListNode *f=head;
        ListNode *s=head;
        ListNode *snn=head;
        while(f!=NULL&&f->next!=NULL){  //快指针走两步,慢指针走一步,快指针走完,慢指针刚好在中间
            s=s->next;
            f=f->next->next;
        }
        if(f!=NULL){
                s=s->next;
        }           
                //如果快指针不为空,链表结点为单数,慢指针在最中间
                //比如12345在3,下一个4才是回文判定开始
        snn=reverlist(s); //s是后面回文判定的开始,把s放进去反转
        //1->2->3->4->5 反转后变    1->2->3<-4<-5   此时snn指向5    3的next指向空
    //1->2->3->4->5->6  反转后变   1->2->3->4<-5<-6 此时head在1 s在4 4指向空  snn在6

                            //错误思考的两种情况
        // while(head!=snn){        //所以这个遍历判断是错的  3的下一个是4  4的下一个是空 无法判定相等
        //     if(head->val!=snn->val){     //而且snn变4  next指向空 再next就出错
        //         return false;
        //     }
        //     head=head->next;
        //     snn=snn->next;
        // }
        // while(head->next!=snn||head!=snn){  //1->2->3->4->5奇数情况判定完了
        //     if(head->val!=snn->val){    //1->2->3->4<-5<-6  偶数情况 4指向空
        //         return false;
        //     }                        //错误,奇数情况没有判定成功
        //     head=head->next;         //1->2->3->4->5<-6<-7   5指向空  snn为5的时候,head为3
        //     snn=snn->next;           //                      再下一步 snn为空  head为4出问题
        // }
        // if(head->next!=snn){    //偶数情况判断3和4
        //     if(head->val==snn->val){
        //         return true;
        //     }
        //     return false;
        // }


                        //正确思考
        while(snn!=NULL){           //1->2->3->4->5<-6<-7   5指向空 回文只需要判断到5
            if(snn->val!=head->val){    //5指向空,当snn从7指向5的时候判断最后一个  指向空的时候判断完成
                return false;
            }
            snn=snn->next;
            head=head->next;
        }
        return true;
    }
};

这道题自己写的,想了很久,主要就是调用了空指针->next,现在深刻理解了这个错误,也理解了画图时的失误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值