算法:链表

一 反转链表

1.1题目

给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围: 0≤n≤1000 

要求:空间复杂度 O(1) ,时间复杂度 O(n) 。

如当输入链表{1,2,3}时,

经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

1->2->3变成3->2->1

原题目:反转链表_牛客题霸_牛客网

1.2解决思路及代码

/*
public class ListNode
{
    public int val;
    public ListNode next;
    public ListNode (int x)
    {
        val = x;
    }
}*/
class Solution
{
    public ListNode ReverseList(ListNode pHead)
    {
        //判断如果链表为空或者只有一个元素时,返回本身
        if(pHead==null||pHead.next==null){
            return pHead;
        }
        //current放到第二个位置,作为会插入到首节点之前的节点
        ListNode current=pHead.next;
        //首节点的next的值设为空,因为首节点在反转后会是最后一个节点,最后一个节点的next为空
        pHead.next=null;
        //遍历除了首节点之外的所有节点
        while(current!=null){
            //next作为下一次插入的current值,主要作用是记住遍历元素的后一个位置
            ListNode next=current.next;
            //当前遍历元素,放在首节点的前面
            current.next=pHead;
            //首节点发生改变,首节点为刚刚插到最开始位置的节点
            pHead=current;
            //到一下个遍历的节点,及上次的next
            current=next;
        }
        return pHead;
    }
}

二 链表内指定区间反转

2.1题目

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n),空间复杂度 O(1)。

例如:
给出的链表为 1→2→3→4→5→NULL, m=2,n=4
返回 1→4→3→2→5→NULL

2.2思路以及代码

如果m=2,n=4

dummy(-1)

->

1->2->3->4->5->null
count=012345

pre(指向翻转链表的首节点)

count=1

last(指向不翻转列表后端的首元素)

current

next

一下是c#的代码

using System;
using System.Collections.Generic;

/*
public class ListNode
{
	public int val;
	public ListNode next;

	public ListNode (int x)
	{
		val = x;
	}
}
*/

class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param m int整型 
     * @param n int整型 
     * @return ListNode类
     */
    public ListNode reverseBetween (ListNode head, int m, int n) {
        // write code here
        if(head==null||head.next==null||m==n){
            return head;
        }
        ListNode dummyNode=new ListNode(-1);
        dummyNode.next=head;
        int count=0;
        ListNode current=dummyNode;
        while(current.next!=null&&count<m-1){
            current=current.next;
            count++;
        }
        ListNode pre=current;
        current=current.next;
        ListNode last=current;
        ListNode phead=current;
        current=current.next;
        count+=2;
        while(current!=null&&count<=n){
            ListNode next=current.next;
            current.next=phead;
            last.next=next;
            pre.next=current;
            phead=current;
            current=next;
            count++;  
        }
        return dummyNode.next;
    }
}

2.3java的代码

这种办法更简洁,需要自己去画一遍过程

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param m int整型 
     * @param n int整型 
     * @return ListNode类
     */
    public ListNode reverseBetween (ListNode head, int m, int n) {
        ListNode dummyNode=new ListNode(-1);//创建头结点
        dummyNode.next=head;
        ListNode pre=dummyNode;//pre代表翻转段,前面的元素
        for(int i=0;i<m-1;i++){//确定翻转段前最后一个不动的位置是那个节点
            pre=pre.next;
        }
        ListNode cur=pre.next;
        ListNode next;
        for(int k=0;k<n-m;k++){//这个比上面的简洁精妙,cur永远都是最开始翻转区间的第一个元素,翻转后,是区间的最后一个元素
            next=cur.next;//next表示要放在翻转区间最前面的首元素
            cur.next=next.next;//cur.next永远指向下一个翻转的元素,或者指向不翻转的后端第一个
            next.next=pre.next;//当前元素指向首位置
            pre.next=next;//翻转前的末尾指向此时翻转链表的首元素
        }
        return dummyNode.next;
    }
}

(1)1->2->3->4->5->null

(2)-1->1->2->3->4->5->null

        确定pre指向1,cur指向2,next指向3     next=cur.next;

        -1->1->2->4->5->null   3->4   cur.next=next.next;

        -1->1->2->4->5->null  3->2     next.next=pre.next;

        -1->1->3->2->4->5->null        pre.next=next;

(3)按照这个步骤下去

三 链表中的节点每k个一组翻转

3.1题目

将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。

数据范围: 0≤n≤2000 ,1≤k≤2000 ,链表中每个元素都满足0≤val≤1000
要求空间复杂度 O(1),时间复杂度 O(n)

例如:

给定的链表是1→2→3→4→5

对于 k = 2k=2 , 你应该返回 2→1→4→3→5

对于 k = 3k=3 , 你应该返回 3→2→1→4→5

3.2思路以及代码

使用栈的帮助,不需要太多的思路

using System;
using System.Collections;
using System.Collections.Generic;

/*
public class ListNode
{
	public int val;
	public ListNode next;

	public ListNode (int x)
	{
		val = x;
	}
}
*/

class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode reverseKGroup (ListNode head, int k) {
        // write code here
        if (k <= 1 || head == null)
            {
                return head;
            }
         Stack st = new Stack();
         ListNode newhead = new ListNode(-1);
         newhead.next=head;
         ListNode res=newhead;
            while (head != null)
            {
                st.Push(head);
                head = head.next;
                if(st.Count==k)
                {
                    while (st.Count > 0)
                    {
                        newhead.next = (ListNode)st.Peek();
                        st.Pop();
                        newhead = newhead.next;
                    }
                    newhead.next = head;//最后剩余不足k个的,不翻转,所以让他指向原来的位置
                }
                
            }
            return res.next;
    }
}

四 合并两个排序的链表

4.1题目

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6}

 

4.2思路以及代码

此题比较简单,我用了一个current去判断已经排好的顺序

/*
public class ListNode
{
    public int val;
    public ListNode next;
    public ListNode (int x)
    {
        val = x;
    }
}*/
class Solution
{
    public ListNode Merge(ListNode pHead1, ListNode pHead2)
    {
        // write code here
        ListNode head=new ListNode(-1);
        ListNode current=head;
        while(pHead1!=null&&pHead2!=null){
            if(pHead1.val>pHead2.val){
                current.next=pHead2;
                pHead2=pHead2.next;
            }else{
                current.next=pHead1;
                pHead1=pHead1.next;
            }
            current=current.next;
        }
        if(pHead1!=null){
            current.next=pHead1;
        }else{
            current.next=pHead2;
        }
        return head.next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值