Leetcode-链表
Leetcode-160 找出两个链表的相交节点
思路:设A链表的长度是a+c,B链表的长度是b+c,两个链表的公共部分长度是c,a+c+b=b+c+a。
同时从A和B的头部开始访问链表,当A链表访问到尾部时从B链表的头部开始访问,当B链表访问到尾部时从A链表的头部开始访问。两个链表会同时访问到相同的节点。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode l1 = headA, l2 = headB; while (l1 != l2) { l1 = (l1 == null) ? headB : l1.next; l2 = (l2 == null) ? headA : l2.next; } return l1; }
Leetcode-206反转链表
1、头插法(tips:单链表的head不存放数据,作用就是保存单链表的头)
//迭代 头插法 public ListNode reverseList(ListNode head){ ListNode pre=null; ListNode cur=head; while(cur!=null){ ListNode temp=cur.next; cur.next=pre; pre=cur; cur=temp; } return pre; }
2、递归法
思路:递归实质上时系统帮你压栈的过程,系统在压栈时会保留现场,一个return完以后恢复前一个节点压栈时的现场,最后完成整个链表的翻转。
//递归法 ListNode reverseList(ListNode head){ if(head==null||head.next==null){ return head; } //反转剩余链表并将第一个元素放在列表的结尾 ListNode rest=reverseList(head.next); head.next.next=head; head.next=null; return rest; }
Leetcode-2链表合并:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
1、迭代法
class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { //prehead占住头部位置 ListNode prehead=new ListNode(-1); //pre指针一直在后移 ListNode pre=prehead; while(l1!=null&&l2!=null){ if(l1.val<=l2.val){ //这里pre.next是添加了一个数,指针并没有移动 pre.next=l1; l1=l1.next; }else{ pre.next=l2; l2=l2.next; } //将pre指针后移,不然会一直停留在第一个位置 pre=pre.next; } //将链表里剩余部分存放进去 pre.next=l1==null?l2:l1; return prehead.next; } }
2、递归法
//递归合并 public ListNode mergeTwoLists(ListNode l1,ListNode l2){ //边界条件 if(l1==null){ return l2; }else if(l2==null){ return l1; } /*可以划分为与母问题相似的子问题,可以考虑递归 **选择第一个较小的节点,剩余部分由第一个节点的剩余节点和另一个链表组成选择第一个较小的节点, **剩余部分由第一个节点的剩余节点和另一个链表组成 */ else if(l1.val<l2.val){ l1.next=mergeTwoLists(l1.next,l2); return l1; } else{ l2.next=mergeTwoLists(l1,l2.next); return l2; } }
Leetcode-83从有序链表种删除重复元素
1、递归法
class Solution { public ListNode deleteDuplicates(ListNode head) { //递归法 if(head==null||head.next==null) return head; head.next=deleteDuplicates(head.next); return head.val==head.next.val?head.next:head; } }
2、迭代法
class Solution { public ListNode deleteDuplicates(ListNode head) { //迭代法 //定义一个用于后移的指针 ListNode cur=head; while(cur!=null&&cur.next!=null){ if(cur.val==cur.next.val){ //通过指针跳过下一个节点 cur.next=cur.next.next; }else{ cur=cur.next;//将当前指针向前移动一个 } } return head; } }
Leetcode-19 删除链表的倒数第N个结点(下面使用的dummy结点被称为哑结点,是在链表千米那添加的一个结点,存放位置是数据结点之前,好处是加入哑结点之后可以使数据结点具有前驱结点)
方法1:两次遍历法(超出了时间限制)
public ListNode removeNthFromEnd(ListNode head,int n){ ListNode dummy=new ListNode(0); dummy.next=head; int length=0; //先使用first指针计算链表的长度 ListNode first =head; while(first!=null){ length++; first=first.next; } //设定length为需要遍历的长度 length=length-n; //将first指针重新指向哑结点 first=dummy; //遍历到需要删除结点的前面一个结点 while(length>0){ length--; first=first.next; } first.next=first.next.next; return dummy.next; }
方法2:1次遍历法
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy=new ListNode(0); dummy.next=head; ListNode first=dummy; ListNode second=dummy; for(int i=0;i<=n;i++){ first=first.next; } //这样使second结点移动了length-n个结点,正好到达要删除结点的前面一个结点 while(first!=null){ first=first.next; second=second.next; } second.next=second.next.next; return dummy.next; } }
Leetcode-24两两交换链表中的结点(还是迭代法思考起来更好理解一些orz)
public ListNode swapPairs(ListNode head) { //定义哑结点 ListNode dummy=new ListNode(-1); dummy.next=head; ListNode pre=dummy; while(pre.next!=null&&pre.next.next!=null){ ListNode l1=pre.next; ListNode l2=pre.next.next; //交换结点 l1.next=l2.next; l2.next=l1; pre.next=l2; //令pre结点指向l1 pre=l1; } return dummy.next; }