Leetcode 链表

Leetcode 21

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

示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
我的思路:
双指针法:
一个指针left1指向l1,一个指针left2指向l2.
此时会遇上四种情况:
①left1《left2,且left1.next<left2
②left1<left2,且left1.next>left2
③left1=left2
④left1>left2
第一种情况:left1=left1.next
第二种情况:left2插入到left1的后面,left1=left1.next
第三种情况:第二种相同
第四种情况:left2插入到left1面前
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode MergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null) return l2;
if(l2==null) return l1;

 ListNode left3;//在不破坏l2的前提下充当指针
            ListNode left1 = l1;//l1的指针,此时left1指向整个链表
            ListNode left2 = l2;//l2的指针
            while (left1 != null && left2 != null)
            {
           if(left1.val<left2.val&&left1.next==null)//第五种情况,必须放在第一位,
                {                                   //否则报错
                    left3=new ListNode(left2.val);
                    left1.next=left3;
                    left1=left1.next;
                    left2=left2.next;
                }
              else   if (left1.val < left2.val && left1.next.val > left2.val)//如果当前小于l2,而下一个大于l2
                {
                    left3 = new ListNode(left2.val);//构建新的结点
                    left3.next = left1.next;//插入到l1中
                    left1.next = left3;
                    left2 = left2.next;//l2往后移   
                    left1 = left1.next;      
                }
                             else if(left1.val==left2.val)
                {
                    left3 = new ListNode(left2.val);
                    left3.next = left1.next;
                    left1.next = left3;
                    left2 = left2.next;
                    left1 = left1.next;
                }
                 else if (left1.val > left2.val)//如果没有比l2小的值
                {
                    left3 = new ListNode(left2.val);//构建新的结点
                    left3.next = left1;//插入到最前
                    left1 = left3;
                    left2=left2.next;
                    l1=left1;               //必须要给l1重新赋值!
                }               
                else left1=left1.next;//第一种情况
 }
return l1;
    }
}
执行用时 :
112 ms, 在所有 C# 提交中击败了64.44%的用户
内存消耗 :
25.7 MB, 在所有 C# 提交中击败了25.00%的用户


出现的问题:
第四种情况:没有加上left2=left2.next
第一种情况一定要加上,否则四循环
第四种情况:一定要注意在left1前面插入数字时,l1并没有改变
第五种情况:不能使用第二种情况,必须放在第一个!

Leetcode 82

题目描述:
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
我的思想:
先解决开头,确保开头和开头的下一个是重复数字;
解决中间和结尾:
star记录重复数字的前一个结点,end记录重复数字,然后通过一个函数,返回下一个不重复的结点。
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode DeleteDuplicates(ListNode head) {
if(head==null) return null;
head=HeadProcess(head);
if(head==null||head.next==null) return head;
ListNode start=head,end;
end=start.next;
while(end!=null&&end.next!=null)
{
if(end.val==end.next.val)
{end=HeadProcess(end);
start.next=end;
}
else{
start=start.next;
end=end.next;

}
}
return head;
    }

    ListNode HeadProcess( ListNode head)//将重复的结点输入
    {
  if(head==null) return  null;//递归之后如果为零,则返回
  
  if(head.next==null||head.val!=head.next.val) return head;//递归之后如果下一个不等于
  int temp=head.val;                                       //或者没有下一个也返回
  while(head!=null&&head.val==temp)//记录重复的值
head=head.next;//开始找下一个
return HeadProcess(head);

    }
}
执行用时 :
116 ms, 在所有 C# 提交中击败了51.39%的用户
内存消耗 :
25.8 MB, 在所有 C# 提交中击败了100.00%的用户

Leetcode 61

题目描述:
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

我的思想:构建一个新的链表
首先记录下原有链表的全部的值以及相对应的序号。之后构造字典,计算移位之后的序号,映射原有的值,然后构造开头和结点,从后往前插入。
BUG:list的索引要用【】
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode RotateRight(ListNode head, int k) {
        if(head==null) return null;
        if(k==0) return head;
        
List<int> list=new List<int>();
Dictionary<int,int> dt=new Dictionary<int,int>();
ListNode targer=head;
while(targer!=null)
{
list.Add(targer.val);//统计值和序号
targer=targer.next;
}
if(list.Count==1) return head;
for(int i=0;i<list.Count;i++)
{
dt[((i+1+k)%(list.Count))]=list[i];//计算移位之后的序号
}
targer=new ListNode(dt[1]);//开头
ListNode tail=new ListNode(dt[0]);//结尾
targer.next=tail;

for(int i=dt.Count-1;i>=2;i--)//从后万千插入
{
tail=new ListNode(dt[i]);
tail.next=targer.next;
targer.next=tail;

}
return targer;

    }
}

我的思想二:
不必构造新的链表,只需要得到移位后新的链表的头和尾巴,断开新的链表的头的前面部分,把原来的尾巴与原来的头连接起来即可
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode RotateRight(ListNode head, int k) {
if(head==null||head.next==null||k==0) return head;

ListNode orihead=head;//原来的头
ListNode oriend=null;//原来的尾巴
ListNode newend=null;//新的尾巴
ListNode newhead=null;//新的头
int oriendnum,newendnum,newheadnum;
int count=0;//计算长度

while(orihead!=null)
{
orihead=orihead.next;
count++;
}
if(k%count==0) return head;
if(k>count) k=k%count;
orihead=head;
oriendnum=count;//原来的尾巴序号
newendnum=count-k;//新的尾巴序号
newheadnum=count-k+1;//新的头序号
count=1;
while(head!=null)
{
if(oriendnum==count) oriend=head;//原来的尾巴
if(newendnum==count) newend=head;//新的尾巴
if(newheadnum==count) newhead=head;//新的头
count++;
head=head.next;
}
oriend.next=orihead;//原来的尾巴接原来的头
if(newend!=null)
newend.next=null;//新的尾巴后面断开
return newhead;//返回新的头

    }
}
执行用时 :
112 ms, 在所有 C# 提交中击败了61.39%的用户
内存消耗 :
25.3 MB, 在所有 C# 提交中击败了100.00%的用户
BUG:count一开始不能设置为1,否则会多一个,因为你的while跳出条件为null,所以最后head=null,count也多算一个。

Leetcode 92

题目描述:
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

我的思想:
因为是一趟反转,所以必然使用while和count进行计数。
要设置五个指针:①指向原始的头用于返回②用于指向反转链表的第一个③用于反转中指向下一个④用于反转中被指向⑤用于指向反转链表的前一个
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode ReverseBetween(ListNode head, int m, int n) {
if(head==null||head.next==null||m==n) return head;//当m=n是while里面全为空
int count=0;
ListNode truestart=head;//用于返回
ListNode First=null,attack=null,defense=null;
ListNode start=null;//反转链表的头一个
while(head!=null&&count<=n)//因为n有可能等于count,所以count不能等于n+1
{
count++;
if(count<m-1) head=head.next;
else if(count==m-1) { start=head; head=head.next;}    
else if(count==m) {First=head; defense=First;  head=head.next;}//第一个发转的头
//First.next=null会使得后面全为空
else if(m<count&&count<=n)                                             
{
attack=head;
head=head.next;
attack.next=defense;
defense=attack;
}
}
First.next=head;

if(m==1) return defense;//如果m=1,star会等于null,后面插入的不在truestart后面
 else { start.next=defense;return truestart;}
    }
}
执行用时 :
96 ms, 在所有 C# 提交中击败了98.11%
的用户
内存消耗 :
24.3 MB, 在所有 C# 提交中击败了100.00%的用户

Leetcode 2

题目描述:
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

我的思路:从两条链表中逐个去除数字,相加它们的值。%10存储到新的链表,/10加到任意一个原来的链表。如果原来的链表的下一个为空,则加到temp,并且跳出循环,然后对于长的链表再做一次加法。
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode AddTwoNumbers(ListNode l1, ListNode l2) {
ListNode first=l1,second=l2;
ListNode result=null;
ListNode end=null,num=null;
int temp=0;
while(first!=null&&second!=null)
{
num=new ListNode((first.val+second.val)%10);
if(end!=null)
{end.next=num;
end=end.next;
}
else {result=num;end=result;}//初始赋值!!
if(first.next!=null&&second.next!=null)//下一个还有的情况
{
first.next.val+=(first.val+second.val)/10;
}
else temp=(first.val+second.val)/10;//包括三种情况:长度一样,l1长,l2长


first=first.next;
second=second.next;
}
if(first==null&&second==null)
{  if(temp==0) return result;
else
{  num=new ListNode(temp);end.next=num; return result;  }  
 }
else if(first!=null&&second==null) { end.next=Process(first,temp);  }
else if(first==null&&second!=null) {end.next=Process(second,temp);}
return result;
    }

ListNode Process(ListNode head,int temp)
{
    ListNode start=head;
head.val+=temp;
int test=0;
if(head.val>=10)
{
while(head.val>=10)
{
test=head.val;
head.val=test%10;
if(head.next==null){  ListNode k=new ListNode(test/10);head.next=k; }//要注意next可能会为空
else head.next.val+=test/10;
head=head.next;

}

}
else {return start;}

return start;//BUG:一开始返回head,但是head推移之后会少了之前的数字,测试用例【1】和【9,9,】会出错
}

}
执行用时 :
124 ms, 在所有 C# 提交中击败了83.44%的用户
内存消耗 :
27.7 MB, 在所有 C# 提交中击败了11.11%的用户

Leetcode 147

题目描述:
对链表进行插入排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode InsertionSortList(ListNode head) {
        if(head==null||head.next==null) return head;

ListNode result=head;//结果
ListNode start=head.next;//未排序的开头
ListNode target;//待排序的目标
ListNode end=head;//已排序的结尾
ListNode num;//插入的位置
while(start!=null)
{
target=start;
start=start.next;
if(target.val<end.val)
{
    num=result;                               //一开始把用head代替了result!
if(target.val<=num.val){  target.next=num; result=target; }
else
{
while(num.val<target.val)
{                                //一开始每加下面这一步
    if(num.next.val>=target.val) {  target.next=num.next;num.next=target; }
  num=num.next;
}

}
end.next=start;//打破循环的关键代码
}
else if(end.next!=null)  end=end.next;
}
return result;

    }
}
执行用时 :
112 ms, 在所有 C# 提交中击败了95.92%的用户
内存消耗 :
25.4 MB, 在所有 C# 提交中击败了100.00%的用户

Offer 24反转两个链表

题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

限制:
0 <= 节点个数 <= 5000

我的思路:
①.用两个节点,一个指向原链表第一个,一个指向下一个,当下一个不为零时,用下一个指向上一个。
代码:

 public ListNode ReverseList(ListNode head) {
        if(head==null) return null;
    ListNode p1; ListNode p2=new ListNode(0);
    while(head.next!=null)
    {
        p1=new ListNode(head.val);
        p2=new ListNode(head.next.val);
        p2.next=p1;
        head=head.next;
    }
    return p2;
    }

出现的BUG:只输出了两个节点,因为p1,p2每次都是重新断开连接!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值