微软面试100题系列---约瑟夫环问题

题目
n个数字形成1个圈,数字从0开始。每次从这个圈中删除第m个数字(当前数字为第1个数字),求出这个圈中剩下的最后一个数字;

实现
方法1 单循环链表
思路:将n个节点形成一个不带头节点的单循环链表,设置一个计数器count(初始化为1)统计第几个数字;如果count=m,则删除当前节点,count=1,当前节点前移;否则继续向前遍历,count++;
代码实现:


public class Num18 {

    public static void main(String[] args) {

        Node_18 first=cycleList(17);
        josephusList(first,17,5);

    }

    public static void josephusList(Node_18 first,int n,int m){
        if(n<1 || m<1){
            return;
        }
        if(m==1){
            //the end is the result
        }
        if(n==1){
            System.out.println(first.data);
        }else{
            Node_18 pre=first;
            Node_18 p=first.next;
            int count=2;
            while(pre!=p){
                if(count==m){
                    System.out.println(p.data);
                    pre.next=p.next;
                    p=pre.next;
                    count=1;
                }else{
                    count++;
                    pre=p;
                    p=p.next;
                }   
            }

            System.out.println(p.data);
        }       
    }

    /*
     * create the cycleList to test
     */
    private static Node_18 cycleList(int n){
        Node_18 first=new Node_18(0);
        Node_18 r=first;
        for(int i=1;i<n;i++){
            Node_18 node=new Node_18(i);
            r.next=node;
            r=node;
            r.next=first;
        }
        return first;
    }

}
class Node_18{
    int data;
    Node_18 next;

    public Node_18(int data){
        this.data=data;
        this.next=null;
    }
}

方法2 分析规律
分析规律,找出一个递归式。
最初的n个数字(0,1,…,n-1),最后剩下的数字是关于n和m的方程f(n,m);这n个数字中,第一个被删除的数字为(m-1)%n=k,剩下的数字为(0,1,2,…,k-1,k+1,…,n-1)===>(k+1,…,n-1,0,1,…,k-1),该序列最后剩下的数字也是关于n-1和m的方程:f(n-1,m)===>f(n,m)=f`(-1,m),即最后剩下的数字相同;
删除一个数字后,将剩下的序列重新进行映射,映射后的序列仍是从0开始并且连续的数字,这样第一个被删除的数字是仍是(m-1)%m
k+1 0
k+2 1
…..
n-1 n-k-2
0 n-k-1

k-1 n-2

进行映射,设映射函数p,p(x)=(x-k-1)%n;
逆映射p`(x)=(x+k+1)%n
===>f(n-1,m)=p[f(n-1,m)]=[f(n-1,m)+k+1]%n将k替换
==>f(n,m)=[f(n-1,m)+m]%n n>1
f(n,m)=0 n=1

代码实现:
递归实现:

public static int LastRemaining(int n ,int m){
        if(n==1){
            return 0;
        }
       return (LastRemaining(n-1,m)+m)%n;
    }

非递归实现:

public static int LastRemaining_2(int n,int m){
        int last=0;
        for(int i=2;i<=n;i++){
            last=(last+m)%i;
        }
        return last;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值