约瑟夫环问题

Tags
#算法
10个人围成一个圆圈,编号为1~10,从第一号开始报数,报到3的倍数的人离开,* 一直数下去,直到最后只有一个人,* 求此人编号

解题代码

package com.che.carcheck.rxjava;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * 约瑟夫问题
 * <p>
 * 10个人围成一个圆圈,编号为1~10(令N=10),
 * 从第一号开始报数,报到3(令M=3)的倍数的人离开,
 * 一直数下去,直到最后只有一个人,
 * 求此人编号
 */
public class Question1 {

  @Test
  public void test() {
      int N = 10, M = 3;
      System.out.println("模拟法:最后的人=" + mock(N, M));
      System.out.println("递归法:最后的人=" + recursion(N, M));
  }

  /**
   * 约瑟夫问题的模拟法
   *
   * @param N 人数
   * @param M 离开的报数
   * @return 最后的人
   */
  private int mock(int N, int M) {
      List<Integer> list = new ArrayList<>();
      //初始化数组,代表所有人
      for (int i = 1; i <= N; i++) {
          list.add(i);
      }
      // 每次计数开始的索引
      int startIndex = 0;
      // 删除的位置
      int removeIndex;
      //循环删除
      while (true) {
          // 【起始位置】+【报号数】-1 =【len】
          int len = startIndex + M - 1;
          // 如果 len > list.size(),相当于转了一圈,又重新开始;
          if (len > list.size() - 1) {
              removeIndex = len % list.size();
          } else {
              removeIndex = len;
          }
          list.remove(removeIndex);
          startIndex = removeIndex;
          //只有最后一位时,返回
          if (list.size() == 1) {
              return list.get(0);
          }
      }

  }

  /**
   * 约瑟夫问题的递归法
   * <p>
   * 递推公式:
   * (1)、f[1]=0;
   * (2)、f[i]=(f[i-1]+m)%i; (i>1)
   * <p>
   * 参考:http://www.acmerblog.com/joseph-problem-3394.html
   */
  public int recursion(int N, int M) {
      int s = 0;
      for (int i = 2; i <= N; i++) {
          s = (s + M) % i;
      }
      return s + 1;
  }

}

© fishyer 2022