約瑟夫環問題多解法彙總

【問題】

首先,讓小朋友們圍成一個大圈。然後,隨機指定一個數 m, 讓編號爲 0 的小朋友開始報數。每次喊到 m-1 的那個小朋友要出列唱首歌,並且不再回到圈中,從他的下一個小朋友開始,繼續 0…m-1 報數… 這樣下去… 直到剩下最後一個小朋友,哪個小朋友會在最後表演呢?(注:小朋友的編號是從 0 到 n-1)

如果沒有小朋友,請返回 - 1


【題解一、數組模擬環】

public int Solution1(int n, int m) {
        if (n == 0) {
            return -1;
        }
        int k,index,count;
        boolean[] flag = new boolean[n];
        k = 0; // 記錄循環次數
        index = 0; // 遊標,記錄數組下標
        count = 0; // 記錄跳出個數
        while (count < n-1) {
            count ++;
            // 當k=m的時候,不進入循環
            while (k < m) {
                // 當前數值未出列,則循環次數+1,當前數值已出列,則不處理
                if (!flag[index]) {
                    // 跳出該數值
                    if (k == m-1) {
                        flag[index] = true;
                    }
                    k++;
                }
                index ++;
                if (index == n) {
                    index = 0;
                }
            }
            k = 0;
        }
        index = 0;
        while (index < n) {
            if (!flag[index]) break;
            index ++;
        }

        return index;
    }

PS:可以用list(arraylist或者linkedlist來代替普通數組、這類動態數組在該類問題上可以提升效率)


【題解二、鏈表模擬】


class ListNode {
 
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}
 
public class Solution {
 	// 鏈表解法一
    public int Solution2(int n, int m) {
 
        if (n <= 0 || m <= 0) {
            return -1;
        }
 
        ListNode head = new ListNode(0);
        ListNode node = head;
        for (int i = 1; i < n; i++) {
            node.next = new ListNode(i);
            node = node.next;
        }
        node.next = head;
 
        int k = 0;
        while (node.next != node) {
            if (++k == m) {
                node.next = node.next.next;
                k = 0;
            } else {
                node = node.next;
            }
        }
 
        return node.val;
    }

	// 鏈表解法二
    public int Solution3(int n, int m) {
        int index,count,k;
        // 建立鏈表
        ListNode p; // 鏈表遊標
        ListNode head = new ListNode(0); // 表頭
        p = head;
        index = 1;
        while (index < n) {
            ListNode l = new ListNode(index);
            p.next = l;
            p = p.next;
            index ++;
        }
        p.next = head; // 構成閉環

        k = 0;
        p = head;
        // 當只有一個節點的時候跳出
       while (p.next != p) {
           while (k < m - 2) {
               p = p.next;
               k ++;
           }
           k = 0;
           // m-1的節點跳出
           p.next = p.next.next;
           // 把遊標P點位到m位置
           p = p.next;
       }
        return p.val;
    }
 
}



【題解三、數學算式】

f(N,M) = ( f(N−1,M) + M ) % N

// 非遞歸
public int Solution4(int n, int m) {
        if (n <= 0 || m <= 0) {
            return -1;
        }
        int num = 0;
        for (int i = 2; i <= n; i++) {
            num = (num + m) % i;
        }
        return num;
    }

// 遞歸算法
public int Solution5(int n, int m) {
        if (n <= 0 || m <= 0) {
            return -1;
        }

        if (n == 1) return 0;

        return (Solution5(n-1,m) + m) % n;
    }
發佈了165 篇原創文章 · 獲贊 852 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章