2021年10月28日 链表的递归 奇偶链表

删除链表倒数第N个节点

 在自己的版本上参考大佬修改后的代码

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(n--)
        fast=fast->next;
    while(fast&&fast->next){
        slow=slow->next;
        fast=fast->next;
    }
    if(fast==NULL) return head->next;
    slow->next=slow->next->next;
    return head;
}

很奇怪啊,为什么判断条件有fast呢?原来是为了满足一些特殊数据啊!

 

自己写的话要分很多类,但是在这里做判断确实更好! 


 java后序遍历递归回溯法:(来自力扣大佬)

我自己感觉if(num==n)这个条件有点问题,应该是"!=",这样后面才会做;

至于"node==null"的时候是返回0还是返回1,也应该再想想。

public ListNode removeNthFromEnd(ListNode head, int n) {
    	int traverse = traverse(head, n);
    	if(traverse == n)
    	    return head.next;
    	return head;
    }
    
    private int traverse(ListNode node, int n) {
        if(node == null)
            return 0;
        int num = traverse(node.next, n);
        if(num == n)
            node.next = node.next.next;
        return num + 1;
    }

 反转链表 

方法一:三指针迭代

List Reverse(List L){
    if(!L) return NULL;
    List temp,nxt;  //两个光标,nxt用来保存temp后面一个节点, 
    temp=L->Next;   //这里L反而可以变了,因为是尾巴不是头结点, 
    L->Next=NULL;   
    while(temp){
        nxt=temp->Next;//先用nxt保存 
        temp->Next=L;//指向L(尾巴),可以理解为入队 
        L=temp;//队伍尾巴更新(有点像堆栈的top) 
        temp=nxt;//更新temp的值 
    }
    return L;
}

 方法二:递归

public ListNode reverseList(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }

    "调用递推公式反转当前结点之后的所有节点"
    "返回的结果是反转后的链表的头结点"
    ListNode newHead = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return newHead;
}

反转前N个节点 

递归(java): 

ListNode topNSuccessor = null;

private ListNode reverseTopN(ListNode head, int n) {
    if (n == 1) {
        topNSuccessor = head.next;
        return head;
    }

    ListNode newHead = reverseTopN(head.next, n-1);
    head.next.next = head;
    head.next = topNSuccessor;
    return newHead;
}

迭代 (C)头插法

image.png

truct ListNode *reverseBetween(struct ListNode *head, int left, int right) {
    // 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
    struct ListNode *dummyNode = malloc(sizeof(struct ListNode));
    dummyNode->val = -1;
    dummyNode->next = head;

    "找到起点的前一个节点"
    struct ListNode *pre = dummyNode;
    for (int i = 0; i < left - 1; i++) {
        pre = pre->next;
    }
    
    "开始头插法"
    struct ListNode *cur = pre->next;
    struct ListNode *next;
    for (int i = 0; i < right - left; i++) {
        next = cur->next;
        cur->next = next->next;
        next->next = pre->next;
        pre->next = next;
    }
    return dummyNode->next;
}

92.反转第a个到第b个节点 


public ListNode reverseBetween(ListNode head, int m, int n) {
    if (m == 1) {
        return reverseTopN(head, n);
    }

    ListNode between = reverseBetween(head.next, m-1,n-1);
    head.next = between;
    return head;
}

ListNode topNSuccessor = null;

private ListNode reverseTopN(ListNode head, int n) {
    if (n == 1) {
        topNSuccessor = head.next;
        return head;
    }

    ListNode newHead = reverseTopN(head.next, n-1);
    head.next.next = head;
    head.next = topNSuccessor;
    return newHead;
}

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right)
    {
      ListNode temp=head;
      List<ListNode> list=new ArrayList<>();"创建数组作为栈"

      "全部节点入栈"
      while(temp!=null)
      {
          list.add(temp);
          temp=temp.next;
      }

      "小细节处理left和right,注意这里"
      left=left-1;
      right=right-1;

      for(int i=right;i>left;i--)
      {   
          list.get(i).next=list.get(i-1);"出栈并且反转"
      }   

      "没看得很懂"
      list.get(left).next=(right==list.size()-1?null:list.get(right+1));
      
      
      if(left==0)"如果从头结点开始反转"
      {
         return list.get(right);
      }
      else{"不是从头节点开始反转,那么就将段的最右边节点出栈然后接到原链表后"
          list.get(left-1).next=list.get(right);
          return head;
      }
    }
}

编程狂想曲https://leetcode-cn.com/problems/reverse-linked-list/solution/yi-bu-yi-bu-jiao-ni-ru-he-yong-di-gui-si-67c3/https://leetcode-cn.com/problems/reverse-linked-list/solution/yi-bu-yi-bu-jiao-ni-ru-he-yong-di-gui-si-67c3/ 这里提供了怎么写递归的思路。


203 移除链表元素

struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* dummyHead = malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode* temp = dummyHead;
    while (temp->next != NULL) {
        if (temp->next->val == val) {
            temp->next = temp->next->next;
            "如果一样那么就temp指针在temp->next的基础上后移一格"
        } 
        else {
            temp = temp->next;"如果不一样temp后移一格"
        }
    }
    return dummyHead->next;
}

        真是掉到坑里了,一开始这里还去特别设计如果有连续相同的数要怎么删除,其实哪里需要考虑这个 ,直接交给循环了就好了,这里自然而然地会帮你去后移指针。

递归版本:

(等待更新)

奇偶链表 

基本思路:用双指针来爬奇偶点,注意要同时爬,用一个节点来保存偶数链表的头(及原链表的第二个 节点),奇数链表的表头自然就是原始的head了。

struct ListNode* oddEvenList(struct ListNode* head) {
    if (head == NULL) {
        return head;
    }
    struct ListNode* evenHead = head->next; "先存下偶数链表的头"
    struct ListNode* odd = head;  "odd指针指向第一个奇数节点,即头结点"
    struct ListNode* even = evenHead; "even指针指向第一个偶数节点,即第二个节点"
    while (even != NULL && even->next != NULL) {
        odd->next = even->next; "这里用even->next和odd->next->next好像没什么不同"
        odd = odd->next; "自我迭代"
        even->next = odd->next; "同上"
        even = even->next; "同上"
    }
    odd->next = evenHead;"偶数链表接到奇数链表后"
    return head;
}

 ATTETION :这里要注意while的循环条件,不能换成奇数判断,也不能写"odd->next&&even->next",这样子写会出错。因为偶数比奇数大,所以我们用偶数来判断是否遍历完。

(这个点吃了大亏)

猜你喜欢

转载自blog.csdn.net/LEewhITe2003/article/details/121012755