单链表

链表相关的操作,主要包括删除一个节点,增加一个节点,寻找一个节点等。
以下为LeetCode上关于链表的个人解题笔记。

1.反转链表

/**
     * 使用一个列表来保存所有节点的值
     * 然后使用prev指向前一个节点,cur指向当前节点
     * 每次插入一个的时候,将prev与cur连接起来,并更新prev
     * 
     * @param head
     * @return
     */
     public ListNode reverseList(ListNode head) {
          ArrayList<Integer> values = new ArrayList<>();
          while(head != null){
              values.add(head.val);
              head = head.next;
          }
          ListNode first = null;
          ListNode prev = null;
          ListNode cur = null;
          boolean isFirst = true;
          for(int i=values.size()-1 ; i>=0; i--){
              if(isFirst){
                  //第一次进来初始化first,并且让prev也指向first
                  isFirst = false;
                  first = new ListNode(values.get(i));
                  prev = first;
              }
              else{
                  cur = new ListNode(values.get(i));
                  prev.next = cur;//将前一个节点与当前节点相连
                  prev = cur;//更新前一个节点
              }
          }
          return first;
     }

2.删除链表中值等于某个数的所有元素。

    /**
     * 还是使用prev,cur指向前一个节点和当前节点
     * 分要删除的节点是不是头结点两种情况
     * 如果是头结点,则更新头结点,prev,cur;
     * 如果不是不是头结点,则更改prev.next的指向,使其指向cur.next;
     * @param head
     * @param val 要删除元素的值
     * @return
     */
    public ListNode removeElements(ListNode head, int val) {
        ListNode prev = head;
        ListNode cur  = head;
        boolean needUpdateFirst = true;
        while(cur!=null){
            if(cur.val == val){
                if(needUpdateFirst){//头结点的值等于val,更新头结点
                    head = head.next;
                    prev = head;
                    cur = head;
                }
                else{ //等于val的节点不是位于头结点
                    prev.next = cur.next;
                    cur = cur.next;
                }
            }
            else{
                needUpdateFirst = false;
                prev = cur;
                cur = cur.next;
            }
        }
        return head;
    }

3.查找两个单链表的交点开始的节点。

方法一:
主要思想是遍历两个链表保存到两个ArrayList中;
然后从后往前比较这两个ArrayList的相同项个数;
最后将这些相同项连接起来返回。

     public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            ArrayList<Integer> valuesA = new ArrayList<>();
            ArrayList<Integer> valuesB = new ArrayList<>();
            ListNode curA = headA;
            ListNode curB = headB;
            //遍历两个链表保存到两个ArrayList中
            while(curA != null){
                valuesA.add(curA.val);
                curA = curA.next;
            }
            while(curB!= null){
                valuesB.add(curB.val);
                curB = curB.next;
            }
            //然后从后往前比较这两个ArrayList的相同项个数
            int count = 0;
            for(int i= valuesA.size()-1, j = valuesB.size()-1; i>=0 && j>=0; i--,j--){
                if(!valuesA.get(i).equals(valuesB.get(j))){
                    break;
                }
                count++;
            }
            if(count == 0){
                return null;
            }
            ListNode first = null, prev = null, cur = null;
            boolean isFirst = true;
            //将这些相同项连接起来返回。
            while(count>0){
                int index = valuesA.size() - count;
                count --;
                if(isFirst){
                    isFirst = false;
                    first = new ListNode(valuesA.get(index));
                    prev = first;
                    cur = first;
                }
                else{
                    cur = new ListNode(valuesA.get(index));
                    prev.next = cur;
                    prev = cur;
                }
            }
            return first;
        }

方法二:来自LeetCode
1.根据两个ListNode长度是否相等,有不同的执行效果。
2.当长度相等时,最多执行n次(n次时同时为null)。
例如[3,4,2,3] 和[3,4,2,4]
[3,4,1,2]和[5,6,1,2]
3.当长度不等时,最多执行m+n+2次(最后同时为空)
例如对于[3,1,4] 和[4,5,1,2]
下面的a会经过 3,1,4,null,4,5,1,2,null
下面的a会经过 4,5,1,2,null,3,1,4,null

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            if(headA == null || headB == null) return null;
            ListNode a = headA;
            ListNode b = headB;
            while(a!=b){
                a = a==null? headB: a.next;
                b = b==null? headA: b.next;
            }
            return a;
        }

4.将两个单项链表相加,每个节点的值都为0-9,且没有前导0,需要逢十个进一。

第一种方法:
    1.遍历将链表的值保存到ArrayList中
    2.然后将短的ArrayList依次加到长的ArrayList对应位置
    3.最后更新长的ArrayList的进位
    4.利用长的ArrayList从前往后构建链表
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
            if(l1==null || l2==null) return null;
            ArrayList<Integer> firstValues = new ArrayList<>();
            ArrayList<Integer> secondValues = new ArrayList<>();

            ListNode first = l1;
            ListNode second = l2;
            while(first!=null){
                firstValues.add(first.val);
                first = first.next;
            }
            while(second != null){
                secondValues.add(second.val);
                second = second.next;
            }
            int sizeFirst = firstValues.size();
            int sizeSecond = secondValues.size();
            ListNode result;
            if(sizeFirst>sizeSecond){
                result = add(firstValues, secondValues);
            }
            else{
                result = add(secondValues, firstValues);
            }
            return result;
        }
        //确保firstValues比secondValues数据多
        private ListNode add(List<Integer> firstValues, List<Integer> secondValues){
            //将第二个加到第一个上
            for(int i=secondValues.size()-1, j= firstValues.size()-1; 
                    i>=0 && j>=0; i--,j--){
                firstValues.set(j, firstValues.get(j)+secondValues.get(i));
            }
            //更新第一个为10的节点
            for(int i = firstValues.size()-1; i>=0; i--){
                int value = firstValues.get(i);
                if(value>=10){
                    firstValues.set(i, value-10);//更新当前值
                    if(i>=1){
                        firstValues.set(i-1, firstValues.get(i-1)+1);
                    }
                    else{
                        ArrayList<Integer> arrayList = new ArrayList<>();
                        arrayList.add(1);
                        arrayList.addAll(firstValues);
                        firstValues = arrayList;
                    }
                }
            }
            //构造链表
            ListNode first = null, prev = null, cur = null;
            boolean isFirst = true;
            for(int i=0; i<firstValues.size(); i++){
                if(isFirst){
                    isFirst = false;
                    first = new ListNode(firstValues.get(i));
                    prev = first;
                }
                else{
                    cur = new ListNode(firstValues.get(i));
                    prev.next = cur;
                    prev = cur;
                }
            }
            return first;
        }

第二种方法:更优,将进位问题和构建链表放在一起处理了。
使用两个栈来保存遍历的值
然后利用两个栈的值从后往前构建链表

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if(l1==null || l2==null) return null;
        Stack<Integer> firstValues = new Stack<>();
        Stack<Integer> secondValues = new Stack<>();

        ListNode first = l1;
        ListNode second = l2;
        while(first!=null){
            firstValues.add(first.val);
            first = first.next;
        }
        while(second != null){
            secondValues.add(second.val);
            second = second.next;
        }
        ListNode listNode = new ListNode(0);
        int sum = 0;
        while( !firstValues.isEmpty() || !secondValues.isEmpty()){
            if(!firstValues.isEmpty()) sum += firstValues.pop();
            if(!secondValues.isEmpty()) sum+= secondValues.pop();
            listNode.val = sum%10;//更新当前链表第一个节点的值
            ListNode head = new ListNode(sum/10);//创建一个新的头结点
            head.next = listNode; //将新的头结点与原来的链表连接
            listNode = head;//更新链表
            sum /= 10;
        }
        //确保不含有前导0
        return listNode.val == 0 ? listNode.next: listNode;
        }

5.给定一个单链表,将所有奇数节点组合在一起,然后是偶数节点。

请注意,我们正在谈论节点号而不是节点中的值。
解决方法:
遍历ListNode到ArrayList中
然后利用ArrayList构建链表
public ListNode oddEvenList(ListNode head) {
        if(head == null){
            return null;
        }
        ListNode myHead = head;
        ArrayList<Integer> arrayList = new ArrayList<>();
        while(myHead!=null){
            arrayList.add(myHead.val);
            myHead = myHead.next;
        }
        ListNode first =null;
        ListNode prev = null;
        ListNode cur = null;
        boolean isFirst = true;
        for(int i=0;i<arrayList.size();i+=2){
            if(isFirst){
                isFirst = false;
                first = new ListNode(arrayList.get(i));
                prev = first;
            }
            else{
                cur = new ListNode(arrayList.get(i));
                prev.next = cur;
                prev = cur;
            }
        }
        for(int i=1; i<arrayList.size();i+=2){
            cur = new ListNode(arrayList.get(i));
            prev.next = cur;
            prev = cur;
        }
        return first;

    }

6.重排单向链表

给定链表 L: L0→L1→…→Ln-1→Ln,
将该链表重排为: L0→Ln→L1→Ln-1→L2→Ln-2→…
/**
     * 遍历单链表将值存到ArrayList中
     * 然后使用ArrayList中的值更新原来head链表的值
     * 如果为奇数个节点,则将中间的那个奇数节点(当然也包括只有一个节点的情况),更新对应的值。
     * @param head
     */
    public void reorderList(ListNode head) {
        if(head == null){
            return;
        }
        ListNode myHead = head;
        ArrayList<Integer> arrayList = new ArrayList<>();
        // 遍历单链表将值存到ArrayList中
        while(myHead!=null){
            arrayList.add(myHead.val);
            myHead = myHead.next;
        }
        int left = 0, right = arrayList.size()-1;
        myHead = head;
        //然后使用ArrayList中的值更新原来head链表的值
        while(left < right){
            myHead.val = arrayList.get(left);
            myHead.next.val = arrayList.get(right);
            if(myHead.next != null)
                myHead = myHead.next.next;
            left++;
            right--;
        }
        // 如果为奇数个节点,则将中间的那个奇数节点(当然也包括只有一个节点的情况),更新对应的值。
        if(arrayList.size()%2 != 0){
            myHead.val = arrayList.get(arrayList.size()/2);
        }

    }

7.给定一个链表,返回循环开始的节点。如果没有循环,返回null。

1.方法一:
    关键:将之前遍历过的节点保存到ArrayList中
    每次遇到新的节点,就判断它的下一个节点是否已经在ArrayList
    如果在表明已经存在,则直接返回;
    如果不存在,则将当前节点添加到ArrayList中
        public ListNode detectCycle(ListNode head) {
            if(head == null) return null;
            ListNode myHead = head;
            ArrayList<ListNode> prevListNodes = new ArrayList<>();
            while(myHead != null){
                if(myHead.next != null && prevListNodes.contains(myHead.next)){
                    return myHead.next;
                }
                else{
                    prevListNodes.add(myHead);
                    myHead = myHead.next;
                }
            }
            return null;
        }

2.方法二:来自LeetCode
1.通过步长为1和步长为2的两个指针a,b寻找相遇的位置
2.利用一个新的指针c从头开始,与上述两个节点之一可以是a或者是b进行比较
找到循环开始的第一个节点。
因为找到的相遇节点的位置不同,所以需要进行步骤2
例如:
1.以首节点或尾节点开始循环,找到的相遇就是该节点
[1,2,3,4,1,2,3,4….] 以第一个节点开始循环
[1,2,3,4,4,4,4,….] 以尾节点开始循环
2.以中间节点开始循环,找到的相遇节点是循环的最后一个节点
例如,下面的找到的相遇节点就是4
[1,2,3,4,2,3,4….] 以非首尾节点开始循环,从2开始

public ListNode detectCycle(ListNode head) {
            if(head == null) return null;
            ListNode a = head;
            ListNode b = head;
            boolean hasCycle = false;
            while(a!=null && b!=null){
                a = a.next;
                if(b.next == null) return null;
                b = b.next.next;
                if(a == b){
                    hasCycle = true;
                    break;
                }
            }
            if(!hasCycle) return null;
            ListNode c = head;
            while(c!=a){
                c = c.next;
                a = a.next;
            }
            return c;
        }

8.复制带有随机指针的链表

class RandomListNode {
    int label;
    RandomListNode next, random;
    RandomListNode(int x) { this.label = x; }
    }

1.方法一:

 /**
     * 先构建一个新的链表,并将random指向的节点保存到ArrayList中
     * 然后从ArrayList中依次取出random节点,并与新链表的对应节点向比较,如果相等则赋值为对应节点。
     * @param head
     * @return
     */
    public RandomListNode copyRandomList(RandomListNode head) {
            RandomListNode myHead = head;
            RandomListNode copyFirst = null;
            RandomListNode prev = null;
            RandomListNode cur = null;
            boolean isFirst = true;
            ArrayList<RandomListNode> keepRandoms = new ArrayList<>();
            while(myHead != null){
                if(isFirst){
                    isFirst = false;
                    copyFirst = new RandomListNode(myHead.label);
                    prev = copyFirst;
                }
                else{
                    cur = new RandomListNode(myHead.label);
                    prev.next = cur;
                    prev = cur;
                }
                keepRandoms.add(myHead.random);
                myHead = myHead.next;
            }
            myHead = copyFirst;
            for(int i=0; i<keepRandoms.size(); i++){
                if(keepRandoms.get(i) != null){
                    //如果对应的random不为空的话,则找到对应的相等节点并返回。
                    myHead.random = getTheEqualNode(copyFirst, keepRandoms.get(i));
                }
                myHead = myHead.next;
            }
            return copyFirst;
    }
    public RandomListNode getTheEqualNode(RandomListNode first, RandomListNode random){
        RandomListNode randomCopy = random;
        RandomListNode curFirst = first;
        RandomListNode curFirstCopy = curFirst;
         while(curFirst != null){
             randomCopy = random;
             curFirstCopy = curFirst;
             boolean hasFind = true;
             while(randomCopy!=null){
                 if(randomCopy.label!= curFirstCopy.label ){
                     hasFind = false;
                     break;
                 }
                 randomCopy = randomCopy.next;
                 curFirstCopy = curFirstCopy.next;
             }
             if(hasFind){
                 return curFirst;
             }
             curFirst = curFirst.next;
         }
         return null;
    }

2.方法二:来自LeetCode

public RandomListNode copyRandomList(RandomListNode head) {
  if (head == null) return null;

  Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();

  // loop 1. copy all the nodes
  RandomListNode node = head;
  while (node != null) {
    map.put(node, new RandomListNode(node.label));
    node = node.next;
  }

  // loop 2. assign next and random pointers
  node = head;
  while (node != null) {
    map.get(node).next = map.get(node.next);
    map.get(node).random = map.get(node.random);
    node = node.next;
  }

  return map.get(head);
}

9.删除有序链表的节点,使得所有值只出现一次

给定一个排序的链接列表,删除所有重复项,使每个元素只显示一次。
例如, 给定1-> 1-> 2,返回1-> 2。 给定1-> 1-> 2-> 3-> 3,返回1-> 2-> 3。

 /**
     * 总的来说就是不断地判断当前节点与前一个节点是否相等
     * 如果相等,就删除当前节点(即将前一个节点与当前节点的下一个节点相连接),然后更新当前节点
     * 如果不相等,则更新前一个节点为当前节点,然后更新当前节点
     * @param head
     * @return
     */
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null){
            return null;
        }
        ListNode prev = head;//指向前一个
        ListNode cur = head.next;
        while(cur != null){
            //如果前一个节点等于当前节点,让前一个节点与当前节点的后一个节点连接起来(删除了当前节点)
            if(prev.val == cur.val){
                prev.next = cur.next;
            }
            //如果前一个节点不等于当前节点,则更新当前节点的
            else{
                prev = cur;
            }
            //更新当前节点
            cur = cur.next;
        }
        return head;
    }

10.删除有序链表中所有出现两次及两次以上的节点(第九题升级版)

1.方法一;利用prev,cur,curnext三个指针
/**
     * 总的来说利用prev指向前一个不相同节点,利用cur指向当前节点,curnext指向下一个节点,
     * 1.如果 cur.val == curnext.val,那么就不断更新curnext直到不等于cur;
         * 将cur更新为curnext
         * 如果是需要更新head节点的话,
         *       就更新head节点
         * 如果不需要的话
         *      然后将prev.next与curnext指向的节点相连接
         * 
     * 2.如果cur.val != curnext.val,那么就设置needUpdateFirst为false,
     * 然后更新prev为cur,并且将cur更新为curnext
     * @param head
     * @return
     */
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null) return null;
        ListNode prev = null;
        ListNode cur = head;
        ListNode curnext = null;
        boolean needupdateFirst = true;

        while(cur != null){
             curnext = cur.next;
            if(curnext != null && cur.val == curnext.val){
                while(curnext != null && cur.val == curnext.val){
                    curnext = curnext.next;
                }
                cur = curnext;
                if(needupdateFirst){
                    head = cur;
                }
                else{
                    prev.next = cur;
                }
            }
            else{
                needupdateFirst = false;
                prev = cur;
                cur = curnext;
            }

        }
        return head;
    }
   方法二:利用一个ArrayList A来保存所有遍历链表的值,
然后将ArrayList A中只出现一次的值保存到ArrayList B中
将利用ArrayList B构建一个链表即可。

11.旋转队列

给定列表,将列表向右旋转k个位置,其中k是非负数。 
例如: 给定1-> 2-> 3-> 4-> 5-> NULL和k = 2, 返回4-> 5-> 1-> 2-> 3->空。
/**
     * 解题思路:
     * 1.首先遍历统计链表的节点个数,计为length
     * 2.然后将k对length求余
     * 3.再次遍历链表,每遍历一个节点cur,length减一,记录下一个节点next
     *      如果此时length == k 表明已经找到新链表的头结点,将cur.next改为null,将next节点赋给myFirst
     *      如果此时length == 0;将旧链表的最后一个节点与原来的头结点相连
     *      其他情况,继续遍历下一个节点
     * @param head
     * @param k
     * @return
     */
    public ListNode rotateRight(ListNode head, int k) {
        if(head ==null || k <= 0) return head;
        ListNode cur = head;
        int length = 0;
        while(cur != null){
            length ++;
            cur = cur.next;
        }
        k = k % length;
        if(k ==0) return head;
        ListNode myFirst = null;
        ListNode next = null;
        cur = head;
        while(cur != null){
            length--;
            next = cur.next;
            if(length == k){//此时找到新的头结点
                cur.next = null;
                myFirst = next;
                cur = myFirst;
            }
            else if(length == 0){//将旧链表的最后一个节点与头结点相连
                cur.next = head;
                break;
            }
            else cur = cur.next;
        }
        return myFirst;
    }

12.合并有序列表,使得合并后的列表仍然有序

1.方法一:合并l2到l1上

 /**
     * 核心思想:将l2合并到l1上,l2插入到l1有三个位置队首,队中,队尾
     *l1中使用两个指针prev1,cur1
     *l2中使用一个指针cur2
     *  内层循环
         *  将prev1指向链表一中小于等于cur2的最后一个节点,
         *  cur1指向大于cur2或为null的节点
        *如果cur1为空,将cur2插入到cur1队尾
        *如果cur1不为空且等于l1,将cur2插入队首
        *否则将cur2插入队列L1中
     * @param l1
     * @param l2
     * @return
     */
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        ListNode cur1 = l1, prev1 = null;
        ListNode cur2 = l2;
        while(cur1 != null && cur2 != null){
            while(cur1 != null && cur2!=null && cur1.val <= cur2.val){
                prev1 = cur1;//不断更新prev1使得prev1指向满足条件的最后一个节点
                cur1 = cur1.next;
            }
            if(cur1 == null){//将cur2插入到cur1队尾
                prev1.next = cur2;
                break;
            }
            else if(cur1 == l1){//将cur2插入队首
                ListNode myFirstNode = new ListNode(cur2.val);
                myFirstNode.next = l1;
                l1 = myFirstNode;
                prev1 = myFirstNode;
            }
            else{//将cur2插入队列L1中
                ListNode insert = new ListNode(cur2.val);
                ListNode oldNext = prev1.next;
                prev1.next = insert;
                insert.next = oldNext;
                prev1 = insert;
            }
            cur2 = cur2.next;
        }
        return l1;

    }

方法二:你可以遍历两个列表并将其放在同一个ArrayList中,然后
对ArrayList进行排序,最后构造一个新的链表。效率低,但是思想简单。

方法三:递归来自LeetCode

public ListNode mergeTwoLists(ListNode l1, ListNode l2){
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        if(l1.val < l2.val){
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else{
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }

13.一对一对的交换链表中的节点

给定一个链表,交换每两个相邻的节点并返回其头。
例如, 给定1-> 2-> 3-> 4,您应该以2-> 1-> 4-> 3的形式返回列表。
要求:
您的算法应该只使用恒定空间。
您不能修改列表中的值,只能改变节点本身。

 /**
     * 核心:更新交换奇数偶数节点,并使用prev记录之前的奇数节点
     * odd指向链表中的奇数节点
     * even指向链表中的偶数节点
     * prev更新后的奇数节点
     * @param head
     * @return
     */
    public ListNode swapPairs(ListNode head) {
        if(head == null) return null;
        ListNode odd = head;
        ListNode even = odd.next;
        boolean first = true;
        ListNode prev = null;
        while(odd != null && even != null){
            odd.next = even.next;//交换奇偶数节点
            even.next = odd;
            if(first){//如果为第一次的话,要更改头结点
                first = false;
                head = even;
            }
            else{//如果不是第一次的话,要更新prev的指向
                prev.next = even;
            }
            prev = odd;//使得prev指向更新后的奇数节点
            odd = odd.next;
            if(odd!=null){
                even = odd.next;
            }

        }
        return head;
    }

14.分区链表

给定一个链表和一个值x,对其进行分区,使得小于x的所有节点都在大于或等于x的节点之前。
您应该保留两个分区中每个分区中节点的原始相对顺序。

例如, 给定1-> 4-> 3-> 2-> 5-> 2和x = 3, 返回1-> 2-> 2-> 4-> 3-> 5。
解决方法:cur用来遍历链表中的每一个节点,prev用来记录cur的前一个节点
 prevLittle用来指向前一个小于x的节点。
/**
     * cur用来遍历链表中的每一个节点,prev用来记录cur的前一个节点
     * prevLittle用来指向前一个小于x的节点。
     * 
     * 
     * 先不考虑左边小于x的节点
     *      如果存在的话,更新prevLittle
     * 然后在大于等于x的节点之后,寻找小于x的第一个节点    
     * 如果找不到的话,直接返回
     * 如果存在的话,删除该中该节点
     * 此时判断prevLittle是否为空
     *      如果为空,则将节点插入到原头结点之前,并更新头结点,最后更新prevLittle
     *      如果不为空,则将该节点插入到prevLittle之后,最后更新prevLittle
     * 继续从链表中寻找下一个小于x的节点,如果找到的话,将其先删除,然后插入到prevLittle之后,并更新prevLittle
     * @param head
     * @param x
     * @return
     */
      public ListNode partition(ListNode head, int x) {
            if(head == null) return head;
            ListNode cur = head;
            ListNode prevLittle = null;
            ListNode prev = head;
            while(cur!=null && cur.val <x){//不考虑左边小于x的节点
                prevLittle = cur;
                cur = cur.next;
            }

            while(cur!= null && cur.val>=x){//找到在大于等于x的节点之后,小于x的第一个节点
                prev = cur;
                cur = cur.next;
            }
            if(cur == null) return head;//找不到就满足要求,直接返回
            prev.next = cur.next;//删找到的第一个中间节点
            if(prevLittle == null){//更新头结点
                ListNode newHead = new ListNode(cur.val);
                newHead.next = head;
                head = newHead;
                prevLittle = head;
            }
            else{
                ListNode node = new ListNode(cur.val);
                node.next = prevLittle.next;//将cur.val插入到prevLittle之后
                prevLittle.next = node;
                prevLittle = prevLittle.next;
            }
            cur = cur.next;
            while(cur != null){
                while(cur!= null && cur.val >=x){//继续从链表中寻找下一个小于x的节点,
                    prev = cur;
                    cur = cur.next;
                }
                if(cur != null){//如果找到的话,将其先删除,
                    prev.next = cur.next;//删除下一个找到的节点

                    ListNode insert = new ListNode(cur.val);//然后插入到prevLittle之后,
                    insert.next = prevLittle.next; 
                    prevLittle.next = insert;
                    prevLittle = insert;//更新prevLittle
                    cur = cur.next;
                }
            }
            return head;
       }

15.k个节点为一组进行反转

给定一个链表,一次反转链表k的节点并返回其修改列表。
k是正整数,小于或等于链表的长度。如果节点的数量不是k的倍数,
则最后的剩余节点应保持原样。

要求:您不能更改节点中的值,只有节点本身可能会更改。
只允许恒定的内存。
例如, 给出这个链表:1-> 2-> 3-> 4-> 5 对于k = 2,
您应该返回:2-> 1-> 4-> 3-> 5 对于k = 3,您应该返回:3-> 2-> 1-> 4-> 5

/**
     * 先获取链表的长度length
     * 然后让 extra = length % k
     * 使用一个ListNode nodes[k]数组来保存当前组的节点,
     * 使用prev来保存前一组的最后一个节点,用来连接不同的组
     * 
     * 先nodes中更改节点的指向
     *  如果是第一组,,需要更新头结点,
     *  如果不是第一组,更改prev.next = nodes[k-1](将前一组的最后一个与当前组的第一个连接起来)
     * 最后将prev赋值为nodes[0]
     * @param head
     * @param k
     * @return
     */
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null) return null;
        int length = 0;
        ListNode cur = head;
        while(cur != null){
            length++;
            cur = cur.next;
        }
        if(k > length) return head;
        int extra = length % k;
        ListNode nodes[] = new ListNode[k];
        ListNode prev = null;
        cur = head;
        int index = 0;
        while(cur != null){
            if(length == extra) break;//多余部分不需要处理
            nodes[index] = cur;
            cur = cur.next;
            index++;
            if(index == k){//已经到一组的末尾了
                index = 0;
                for(int i=0; i<k; i++){//更新节点的指向
                    System.out.println(nodes[i].val);
                    if(i == 0) nodes[0].next = nodes[k-1].next;
                    else nodes[i].next = nodes[i-1];
                }
                if(prev == null)  head = nodes[k-1];///表明是第一组,更新头结点的指向
                else prev.next = nodes[k-1]; //不是第一组,将前一组的最后一个与当前组的第一个连接起来
                prev = nodes[0];//更新prev指向当前组的最后一个节点
            }
            length --;
        }
        return head;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值