剑指Offer 45圆圈中最后剩下的数字

本文探讨了经典的约瑟夫环问题,通过两种不同的数据结构——循环链表和LinkedList进行模拟,并最终给出了数学公式的解决方案。

题目描述

0,1。。。n-1这n个数字排成圈;从数字0开始报数(报数开始为1),报道m时,把它踢出去,然后继续从1报数,最后会剩下谁

思路

  1. 模拟游戏过程,直接建一个循环列表,一个一个报数,不过显然这种方法比较复杂;
  2. 不一个一个报数了,直接开上帝模式,指挥下一个出去
  3. 公式的啦,数学之美;

想法进阶

首先循环链表是最模拟的情况,一个一个来,一个一个报数,最后出结果,在人的索引上不会出现问题,但是你需要指针来进行删除,加入有add和remove方法就好了;那么假设用数组或者LinkedList这种不循环的数据结构,模k就显得很重要;你需要关心的就是索引的位置,数组可以利用比如元素=-1,就当成删除;LinkedList呢,自带remove,但是你需要想明白索引;如果有这么一个循环链表,还有remove方法,这道题简直不要太简单;
下面给出的事循环链表和LinkedList的解法;

代码

//完全模拟报数的过程
   static public int LastRemaining_Solution(int n, int m) {
        if (n==0) {
            return -1;
        }
        ListNode node = new ListNode(0);
        ListNode head = node;
        for (int i = 1; i < n; i++) {
            node.next = new ListNode(i);
            node=node.next;
        }
        node.next = head;
        int current = 1;
        ListNode start = head;      //当前报数的这个人
        ListNode back =  head;      //当前报数的前一个;
        while (start!=start.next)
        {
            while (current<m)
            {
                back = start;
                start=start.next;
                current++;
            }
            back.next = start.next;     //相当于从循环中扔了出去;
            start = back.next;
            current = 1;
        }
        return  start.val;
    }
  static public int LastRemaining_Solution2(int n , int m)
    {
        LinkedList<Integer> linkedList = new LinkedList();
        for (int i = 0; i < n; i++) {
            linkedList.add(i);
        }
        int current = 0;            //当前报数(0~m-1)
        int index = 0;              //当前位置的索引
        while (linkedList.size()>1)
        {
            while (current<m-1)
            {
                index++;
                index %=linkedList.size();
                current++;
            }
            linkedList.remove(index);
            current=0;
        }
        return linkedList.peek();
    }

然后我们发现实际上不用模拟过程,直接找到下一个的位置即可;于是就可以修改代码为:

 static public int LastRemaining_Solution2(int n , int m) {
        LinkedList<Integer> linkedList = new LinkedList();
        for (int i = 0; i < n; i++) {
            linkedList.add(i);
        }
        int index = 0;              //当前位置的索引
        while (linkedList.size()>1)
        {
            index = (index+m-1)%linkedList.size();
            linkedList.remove(index);
        }
        return linkedList.peek();
    }

最后就是公式法了
这里写图片描述

收获

  1. 编程编程
  2. 慢慢慢慢来;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值