数三退一问题是,有一圈(500人)孩子,手拉手围成一个圈,从第一个孩子开始数1,第二个孩子数2,第三个孩子数3,这时候数3的孩子退出,从下一个孩子开始数1,一直循环,直到最后剩下一个孩子,问这个孩子的位置?
答案是435.
两种解题思路,一种是将这一组小孩看成一个数组(假设有500个数组),每个元素为boolean型,初始时所有的元素为true,然后开始循环数数,判断剩下元素是否大于1,首先判断元素是否为true,true则继续数,每次数到3时,记录剩下元素个数,同时将数字置零,以便从0开始重新数。下面为一种解法:
public class Count3Quit1{ public static void main(String[] args){ boolean[] kids; kids = new boolean[500]; for(int i = 0; i <kids.length; i++){ kids[i] = true; } int leftNum = kids.length; int countNum = 0; int index = 0; while(leftNum > 1){ if(kids[index]){ countNum++; } if(countNum==3){ kids[index] = false; countNum = 0; leftNum--; } index++; if(index == 500){ index = 0; } } for(int i = 0;i < kids.length; i++){ if(kids[i]){ System.out.println(i); } } } }
另外一种解法是在上面的基础上利用面向对象的思想进行,共有三个类,一个主类,一个孩子类,一个圆圈类。孩子类应该有自己的id以及左手拉的小孩是谁,右手拉的小孩是谁。圆圈类,应该有首位和末尾的孩子,还应该有添加孩子和删除孩子方法:
public class Count3Quit2{ public static void main(String[] args){ Circle c = new Circle(500); int countNum = 0; Kid k = c.firstKid; while(c.count > 1){ countNum++; if(countNum == 3){ countNum = 0; c.delete(k); } k = k.rightKid; } System.out.println(c.firstKid.id); } } class Kid{ int id; Kid leftKid; Kid rightKid; } class Circle{ int count = 0; Kid firstKid,lastKid; Circle(int n){ for(int i = 0; i < n;i++){ add(); } } void add() { Kid k = new Kid(); k.id = count; if(count <= 0){ firstKid = k; lastKid = k; k.leftKid = k; k.rightKid = k; } else { lastKid.rightKid = k; k.rightKid = firstKid; k.leftKid = lastKid; firstKid.leftKid = k; lastKid = k; } count++; } void delete(Kid k){ if(count <=0) { return; } else if(count == 1){ firstKid = lastKid = null; }else { k.leftKid.rightKid = k.rightKid; k.rightKid.leftKid = k.leftKid; if(k == firstKid) { firstKid = k.rightKid; } else if(k == lastKid){ lastKid = k.leftKid; } } count--; } }