从零开始学算法---自定义循环单链表

有这样一道算法题, 假设有20个人围成一个圈,现在从第一个人开始报数,数到3的那个人出列,下一个人继续从1开始报数。。。。如此循环,最后剩下的人是谁?

首先我们定义一个单向循环链表

前文(从零开始学算法--自定义单链表 - 倒霉的菜鸟 - 博客园 (cnblogs.com))中已经自定义了单链表, 单向循环链表唯一的区别就是尾节点的next指针指向首节点,

代码实现也和前文类似,不再赘述

  1 public class SingleCycleLinkedList<E> {
  2 
  3     //首先定义节点内部类Node
  4     class Node<E>{
  5         private E element;
  6         private Node<E> nextNode;
  7         
  8         public Node(E element, Node<E> nextNode){
  9             this.element = element;
 10             this.nextNode = nextNode;
 11         }
 12         
 13         @Override
 14         public String toString() {
 15             return element.toString();
 16         }
 17     }
 18     
 19     private Node<E> firstNode;
 20     
 21     private Node<E> lastNode;
 22     
 23     private int size;
 24     
 25     public void add(E e) {
 26         Node<E> node = firstNode;
 27         //当前为空链表
 28         if (node == null) {
 29             Node<E> newNode = new Node(e, lastNode);
 30             firstNode = newNode;
 31             lastNode = firstNode;
 32         }else {
 33             //当前不是空链表,则向尾部添加
 34             Node<E> newNode = new Node(e, firstNode);
 35             lastNode.nextNode = newNode;
 36             lastNode = newNode;
 37         }
 38         size++;
 39     }
 40     
 41     /**
 42      * 获取指定位置的元素
 43      * @param index
 44      * @return
 45      */
 46     public E get(int index) {
 47         return getNode(index).element;
 48     }
 49     
 50     private Node<E> getNode(int index){
 51         Node<E> node = firstNode;
 52         for (int i = 0; i < index; i++) {
 53             node = node.nextNode;
 54         }
 55         return node;
 56     }
 57     
 58     public int size() {
 59         return size;
 60     }
 61     
 62     /**
 63      * 删除指定位置的元素
 64      * @param index
 65      */
 66     public void remove(int index) {
 67         if(index == 0) {
 68             Node<E> node = firstNode;
 69             firstNode = node.nextNode;
 70             lastNode.nextNode = firstNode;
 71         } else if(index == size-1){
 72             Node<E> node = lastNode;
 73             //找到前一个节点
 74             Node<E> preNode = getNode(index-1);
 75             preNode.nextNode = firstNode;
 76             lastNode = preNode;
 77         }else{
 78             //找到前一个节点
 79             Node<E> preNode = getNode(index-1);
 80             Node<E> nextNode = getNode(index+1);
 81             preNode.nextNode = nextNode;
 82         }
 83         size--;
 84     }
 85     
 86     /**
 87      * 删除指定节点
 88      * @param index
 89      */
 90     public void remove(Node<E> targetNode) {
 91         if (firstNode == targetNode) {
 92             lastNode.nextNode = targetNode.nextNode;
 93             firstNode = targetNode.nextNode;
 94         }
 95         
 96         Node<E> node = firstNode;
 97         for (int i = 0; i < size-1; i++) {
 98             Node<E> preNode = node;
 99             node = node.nextNode;
100             if(node == targetNode) {
101                 preNode.nextNode = node.nextNode;
102             }
103         }
104         size--;
105     }
106 }

再定义一个循环删除的方法

因为链表首位相接,所以我们不能通过Index来判断需要删除哪个元素,只能先定位到起始节点, 然后根据node.nextNode往下个节点移动,每移动3次就执行一次删除动作

给定初始位置Index, 那么起始节点就应该是index-1,  当index为0时, 起始节点为尾节点

 1 public void cycleRemove(int beginIndex, int count) {
 2         Node<E> targetNode;
 3         if (beginIndex == 0) {
 4             targetNode = lastNode;
 5         }else {
 6             targetNode = getNode(beginIndex-1);
 7         }
 8         while (size >1) {
 9             for (int i = 0; i < count; i++) {
10                 targetNode = targetNode.nextNode;
11             }
12             remove(targetNode);
13             System.out.println(targetNode.toString()+"出列");
14             
15         }
16         
17     }

测试方法如下 

public static void main(String[] args) {
        SingleCycleLinkedList myList  = new SingleCycleLinkedList();
        for (int i = 1; i < 21; i++) {
            myList.add(i);
        }
        for (int i = 0; i < myList.size(); i++) {
            System.out.print(myList.get(i).toString()+" ");
        }
        System.out.print("\n");
        myList.cycleRemove(0, 3);
        System.out.print("\n after remove:");
        for (int i = 0; i < myList.size(); i++) {
            System.out.print(myList.get(i).toString()+" ");
        }
    }

运行结果

从零开始学算法---自定义循环单链表

 

上一篇:LeetCode-203-移除链表元素


下一篇:[LeetCode] 99. 恢复二叉搜索树