LeetCode训练营之链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/boker_han/article/details/83929626

一、 add-two-numbers

You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

	 public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
	        //输入参数合法性校验
	        if(l1 == null)
	            return l2;
	        if(l2 == null)
	            return l1;
	        //遍历并对每一位以及上一位相加得到进位进行求和
	        int carry = 0;
	        //返回的结果链表头结点
	        ListNode head = null;
	        ListNode pre = null;
	        while(l1 != null && l2 != null){
	            int sum = l1.val + l2.val + carry;
	            carry = sum / 10;
	            sum = sum % 10;
	            if(head == null){
	                head = new ListNode(sum);
	                pre = head;
	            }else{
	                pre.next = new ListNode(sum);
	                pre = pre.next;
	            }
	            l1 = l1.next;
	            l2 = l2.next;
	        }
	        //两个链表前面的相同长度已经计算完毕,处理未对齐的多余链表节点
	        //存在进位的情况
	        if(carry == 1){
	            while(l1 != null){
	                int sum = l1.val + carry;
	                carry = sum / 10;
	                sum = sum % 10;
	                pre.next = new ListNode(sum);
	                pre = pre.next;
	                l1 = l1.next;
	            }
	            while(l2 != null){
	                int sum = l2.val + carry;
	                carry = sum / 10;
	                sum = sum % 10;
	                pre.next = new ListNode(sum);
	                pre = pre.next;
	                l2 = l2.next;
	            }
	            if(carry == 1)
	                pre.next = new ListNode(1);
	        }else{
	            //不存在进位的情况
	            pre.next = l1 == null ? l2 : l1;
	        }
	        return head;
	    }

二、 reverse-linked-list-ii

Reverse a linked list from position m to n. Do it in-place and in one-pass.

    public ListNode reverseBetween(ListNode head, int m, int n) {
        //输入参数合法性校验
        if(head == null || m < 1 || m > n)
            return head;
        //记录当前所在节点的下标
        int len = 0;
        ListNode temp = head;
        //起始节点的前继节点
        ListNode beforeBegin = null;
        //起始节点
        ListNode begin = null;
        //结束节点
        ListNode end = null;
        //结束节点的后继节点
        ListNode afterEnd = null;
        //第一次遍历记录开始节点的前继节点以及结束节点和链表长度
        while(temp != null){
            len++;
            if(len == m - 1)
                beforeBegin = temp;
            if(len == n){
                end = temp;
                break;
            }
            temp = temp.next;
        }
        //输入参数不合法
        if(end == null){
            return head;
        }
        afterEnd = end.next;
        //确定起始节点
        if(beforeBegin == null){
            begin = head;
        }else{
            begin = beforeBegin.next;
        }
        //逆转指定链表
        ListNode pre = afterEnd;
        ListNode cur = begin;
        ListNode next = null;
        end.next = null;
        while(cur != null){
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        if(beforeBegin == null){
            return pre;
        }else{
            beforeBegin.next = pre;
        }
        return head;
    }

注:此方法并不是完全的一趟遍历逆转链表,而是多于一趟遍历的时间复杂度,这是因为不确认边界值是否正确!


三、partition-list

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

    public ListNode partition(ListNode head, int x) {
        //参数合法性校验
        if(head == null || head.next == null)
            return head;
        //第一个大于x的节点
        ListNode bigHead = null;
        //第一个小于x的节点
        ListNode smallHead = null;
        //小于x的子链表的临时节点
        ListNode tempSmall = null;
        //大于x的子链表的临时节点
        ListNode tempBig = null;
        //遍历形成小链表和大链表
        while(head != null){
            //当前节点值小于x
            if(head.val < x){
                if(smallHead == null){
                    smallHead = head;
                    tempSmall = head;
                }else{
                    tempSmall.next = head;
                    tempSmall = tempSmall.next;
                }
            }else{
                //当前节点值大于等于x
                if(bigHead == null){
                    bigHead = head;
                    tempBig = head;
                }else{
                    tempBig.next = head;
                    tempBig = tempBig.next;
                }
            }
            head = head.next;
        }
        if(tempBig != null){
            tempBig.next = null;
        }
        if(tempSmall != null){
            tempSmall.next = bigHead;
            return smallHead;
        }
        return bigHead;
    }

四、remove-duplicates-from-sorted-list

Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,
Given1->1->2, return1->2.
Given1->1->2->3->3, return1->2->3.

    public ListNode deleteDuplicates(ListNode head) {
        //边界值检测
        if(head == null || head.next == null)
            return head;
        //返回链表的头结点
        ListNode result = null;
        //记录当前节点
        ListNode temp = head;
        while(head != null){
            //节点重复
            if(temp.val == head.val){
                head = head.next;
                continue;
            }
            //节点不重复
            temp.next = head;
            //初始化头结点
            if(result == null){
                result = temp;
            }
            //更新节点,进入下一次循环
            temp = temp.next;
            head = head.next;
        }
        //更新尾节点的下一个节点为null
        temp.next = null;
        return result;
    }

五、remove-duplicates-from-sorted-list-ii

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given1->2->3->3->4->4->5, return1->2->5.
Given1->1->1->2->3, return2->3.

   public ListNode deleteDuplicates(ListNode head) {
           //参数合法性校验
           if(head == null || head.next == null)
               return head;
           //判断相邻节点是否值相等
           ListNode temp = head.next;
           //相邻节点值相等
           if(head.val == temp.val){
               //一直找到节点的值不等于输入参数节点的值或走完全部链表节点,都与输入参数节点的值相等
               while(temp != null && head.val == temp.val){
                   temp = temp.next;
               }
               //从第一个不相等的节点处开始递归删除重复元素
               return deleteDuplicates(temp);
           }else{
               //当前节点head和下一节点值不相等
               head.next = deleteDuplicates(temp);
           }
           return head;
       }

六、 rotate-list

Given a list, rotate the list to the right by k places, where k is non-negative.

For example:
Given1->2->3->4->5->NULLand k =2,
return4->5->1->2->3->NULL.

    public ListNode rotateRight(ListNode head, int n) {
       //参数合法性校验
       if(head == null || head.next == null || n < 1)
           return head;
       ListNode temp = head;
       //遍历链表求出长度
       int len = 1;
       while(temp.next != null){
           temp = temp.next;
           len++;
       }
       //首尾相连,形成环
       temp.next = head;
       //走到返回节点的上一节点
       int steps = len - n % len - 1;
       while(steps != 0){
           head = head.next;
           steps--;
       }
       //记录返回的头结点
       ListNode result = head.next;
       //断开环
       head.next = null;
       return result;
   }

七、remove-nth-node-from-end-of-list

Given a linked list, remove the n th node from the end of list and return its head.

    public ListNode removeNthFromEnd(ListNode head, int n) {
        //参数合法性校验
        if(head == null || n < 1)
            return head;
        //快指针
        ListNode fast = head;
        //慢指针
        ListNode slow = head;
        //快指针先走
        while(fast != null && n != 0){
            fast = fast.next;
            n--;
        }
        //快指针已走到尾节点的下一节点null
        if(fast == null){
            //如果n为0,说明删除的节点是链表头结点;如果不为0,则说明n的值大于链表节点个数,参数n不合法
            if(n == 0)
                return head.next;
        }else{
            //快指针指向链表中的某一节点,此时,快慢指针同时走,直到慢指针走到待删除元素的前继节点
            while(fast.next != null){
                fast = fast.next;
                slow = slow.next;
            }
            //删除指定节点
            ListNode next = slow.next;
            slow.next = next.next;
        }
        return head;
    }

八、swap-nodes-in-pairs

Given a linked list, swap every two adjacent nodes and return its head.

    public ListNode swapPairs(ListNode head) {
       //边界值检测
       if(head == null || head.next == null)
           return head;
       //奇数位置节点形成的链表的头结点
       ListNode oddHead = head;
       //偶数位置节点形成的链表的头结点
       ListNode oddTemp = head;
       ListNode evenHead = head.next;
       ListNode evenTemp = head.next;
       //按照节点位置的奇偶性拆分链表
       while(evenTemp != null){
           oddTemp.next = evenTemp.next;
           oddTemp = oddTemp.next;
           if(oddTemp == null)
               break;
           evenTemp.next = oddTemp.next;
           evenTemp = evenTemp.next;
       }
       //更新链表尾节点的next指针域
       if(oddTemp != null)
           oddTemp.next = null;
       if(evenTemp != null)
           evenTemp.next = null;
       //更新变量用于下面两个子链表的连接
       evenTemp = evenHead;
       oddTemp = oddHead;
       //连接由每一对节点构成的子链表
       ListNode link = null;
       //合并链表,偶数链表节点在前,奇数链表节点在后
       while(evenTemp != null && oddTemp != null){
           ListNode evenNext = evenTemp.next;
           evenTemp.next = oddTemp;
           if(link == null){
               link = oddTemp;
           }else{
               link.next = evenTemp;
               link = oddTemp;
           }
           oddTemp = oddTemp.next;
           evenTemp = evenNext;
       }
       //偶数链表还有剩余节点
       while(evenTemp != null){
           link.next = evenTemp;
           link = evenTemp;
           evenTemp = evenTemp.next;
       }
       //奇数链表还有剩余节点
       while(oddTemp != null){
           link.next = oddTemp;
           link = oddTemp;
           oddTemp = oddTemp.next;
       }
       return evenHead;
   }

九、reverse-nodes-in-k-group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.

   	public ListNode reverseKGroup(ListNode head, int k) {
   	   //参数合法性校验以及边界值检测
   	   if(head == null || head.next == null || k < 2)
   	       return head;
   	   //当前待翻转的链表的第一个节点
   	   ListNode begin = head;
   	   //当前待翻转的链表的最后一个节点
   	   ListNode end = head;
   	   //下一组待翻转的链表头结点
   	   ListNode nextBegin = null;
   	   int i = 0;
   	   for( ; i < k - 1 ; i++){
   	       end = end.next;
   	       if(end == null)
   	           return begin;
   	   }
   	   if(end == null)
   	       return begin;
   	   nextBegin = end.next;
   	   ListNode pre = reverseKGroup(nextBegin,k);
   	   ListNode next = null;
   	   while(begin != nextBegin){
   	       next = begin.next;
   	       begin.next = pre;
   	       pre = begin;
   	       begin = next;
   	   }
   	   return pre;
   	}

十、copy-list-with-random-pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.Return a deep copy of the list.

     public RandomListNode copyRandomList(RandomListNode head) {
           //输入参数合法性校验
           if(head == null)
               return null;
           //第一步,插入复制节点
           RandomListNode temp = head;
           while(temp != null){
               RandomListNode copy = new RandomListNode(temp.label);
               RandomListNode next = temp.next;
               temp.next = copy;
               copy.next = next;
               temp = next;
           }
           //第二步,复制随机指针
           temp = head;
           while(temp != null){
                RandomListNode random = temp.random;
                RandomListNode next = temp.next;
               if(random != null){
                   next.random = random.next;
               }
               temp = next.next;
           }
           //第三步,分离两个链表
           temp = head;
           RandomListNode newHead = temp.next;
           while(temp != null){
               RandomListNode next = temp.next;
               RandomListNode tempNext = next.next;
               temp.next = tempNext;
               if(tempNext == null){
                   next.next = tempNext;
                   break;
               }else{
                   next.next = tempNext.next;
               }
               temp = temp.next;
           }
           return newHead;
       }

十一、 linked-list-cycle

Given a linked list, determine if it has a cycle in it.

      public boolean hasCycle(ListNode head) {
          //参数合法性校验
          if(head == null || head.next == null)
              return false;
          //快指针
          ListNode fast = head;
          //慢指针
          ListNode slow = head;
          while(fast != null){
              fast = fast.next;
              slow = slow.next;
              if(fast != null){
                  fast = fast.next;
              }
              if(slow == fast)
                  break;
          }
          if(fast == null)
              return false;
          return true;
      }

linked-list-cycle-ii

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

        public ListNode detectCycle(ListNode head) {
          if(head == null || head.next == head)
              return head;
          //第一步,快慢指针判断是否存在环
          ListNode fast = head.next;
          ListNode slow = head;
          while(fast != slow && fast != null){
              fast = fast.next;
              slow = slow.next;
              if(fast != null){
                  fast = fast.next;
              }else{
                  return null;
              }
          }
          if(fast == null){
              return null;
          }
          //存在环,进一步处理获取环的长度
          fast = fast.next;
          int len = 1;
          while(fast != slow){
              len++;
              fast = fast.next;
          }
          //快慢指针找出入口节点
          fast = head;
          slow = head;
          while(len != 1){
              fast = fast.next;
              len--;
          }
          while(fast.next != slow){
              fast = fast.next;
              slow = slow.next;
          }
          return slow;
      }

reorder-list

Given a singly linked list L: L 0→L 1→…→L n-1→L n, reorder it to: L 0→L n →L 1→L n-1→L 2→L n-2→…

You must do this in-place without altering the nodes’ values.

    public void reorderList(ListNode head) {
       //边界值检测
       if(head == null || head.next == null || head.next.next == null){
           return;
       }
       //后半部分链表的起始节点
       ListNode mid = head;
       //中间变量
       ListNode temp = head;
       //遍历查找节点mid
       while(temp != null){
           temp = temp.next;
           mid = mid.next;
           if(temp != null){
               temp = temp.next;
           }
       }
       //翻转后半部分链表
       ListNode pre = null;
       ListNode cur = mid;
       ListNode next = null;
       while(cur != null){
           next = cur.next;
           cur.next = pre;
           pre = cur;
           cur = next;
       }
       //向前半部分子链表中插入后半部分链表节点
       temp = head;
       while(pre != null){
           if(temp != null){
               next = temp.next;
               temp.next = pre;
               pre = pre.next;
               temp.next.next = next;
               temp = next;
           }
       }
       //断开前半部分最后一个节点指向后半部分最后一个节点的指针
       if(temp != null)
           temp.next = null;
   }

猜你喜欢

转载自blog.csdn.net/boker_han/article/details/83929626