Remember an Ali written test: How do I solve the Joseph ring problem with one line of code

Remember an Ali written test: How do I solve the Joseph ring problem with one line of code

During an interview, I was asked about the communication methods between the processes, but because I didn’t

The Joseph ring problem is a classic question. I guess everyone has heard of it. Then I encountered it in a written test. Below I will use 3 methods to explain this question in detail. The last method is guaranteed. Let you make you pretend.

Description of the problem: N soldiers numbered 1-N sit together to form a circle, starting with the number 1 soldier and report them in turn (1, 2, 3... and so on), the soldier who counts up to m will be killed After death, the soldiers will start counting from 1. Until the last soldier is left, ask for the soldier's number.

1. Method 1: Array

When I encountered this problem for the first time in my freshman year, I did it with an array. I guess most people know how to do it. The method is like this:

Use an array to store 1, 2, 3… n these n numbers, as shown in the figure (here we assume n = 6, m = 3)

Remember an Ali written test: How do I solve the Joseph ring problem with one line of code

Then we keep traversing the array, for the selected number, we make a mark, for example, the number arr[2] = 3 is selected, then we can make a mark, for example, let arr[2] = -1, to indicate The number stored in arr[2] is out.
Remember an Ali written test: How do I solve the Joseph ring problem with one line of code
Then follow this method, keep traversing the array and keep marking until only one element in the array is non-1, so that the remaining element is the element we are looking for. Let me demonstrate:

Is this method simple? The idea is simple, but the coding is not that simple. There are many critical conditions. Every time you traverse to the last element of the array, you have to reset the subscript to 0, and you have to judge whether the element is -1 when traversing. If you are interested, you can write the code, do it in this array method, don't think it is very simple, the coding process is still quite a test.

The time complexity of this approach is O(n * m), and the space complexity is O(n);

2. Method 2: Circular linked list

Those who have studied linked lists are estimated to use linked lists to deal with the Joseph ring problem. Using linked lists to deal with is actually similar to the above process, but when dealing with linked lists, the selected number is no longer marked, but Direct removal, because the time complexity of removing an element from the linked list is very low, O(1). Of course, you can also remove the above array method, but the time complexity of array removal is O(n). So the solution using linked list is as follows:

1. First create a circular linked list to store the elements:
Remember an Ali written test: How do I solve the Joseph ring problem with one line of code

2. Then delete it while traversing the linked list until there is only one node left in the linked list. I will not demonstrate all of them here.
Remember an Ali written test: How do I solve the Joseph ring problem with one line of code

code show as below:

// 定义链表节点
class Node{
    int date;
    Node next;

    public Node(int date) {
        this.date = date;
    }
}

Core code


     public static int solve(int n, int m) {
        if(m == 1 || n < 2)
            return n;
        // 创建环形链表
        Node head = createLinkedList(n);
        // 遍历删除
        int count = 1;
        Node cur = head;
        Node pre = null;//前驱节点
        while (head.next != head) {
            // 删除节点
            if (count == m) {
                count = 1;
                pre.next = cur.next;
                cur = pre.next;
            } else {
                count++;
                pre = cur;
                cur = cur.next;
            }
        }
        return head.date;
    }

    static Node createLinkedList(int n) {
        Node head = new Node(1);
        Node next = head;
        for (int i = 2; i <= n; i++) {
            Node tmp = new Node(i);
            next.next = tmp;
            next = next.next;
        }
        // 头尾串联
        next.next = head;
        return head;
    }

This method is estimated to be the most used by people, with a time complexity of O(n * m) and a space complexity of O(n).

Is there a better way? Answer yes, please look down

Method 3: Recursion

In fact, this problem can be solved by recursion. The idea of ​​recursion is that every time we delete a certain soldier, we renumber these soldiers, and then our difficulty is to find out the mapping relationship between the soldier numbers before and after deletion. .

We define that the return result of the recursive function f(n, m) is the number of the surviving soldiers. Obviously when n = 1, f(n, m) = 1. If we can find the relationship between f(n,m) and f(n-1,m), we can solve it in a recursive way. We assume that the number of people is n, and those who report to m will commit suicide. Then the initial number is


1

m - 2

m - 1

m

m + 1

m + 2

n

After one deletion, the node numbered m is deleted. After deletion, there are only n-1 nodes left. The number conversion relationship before and after deletion is:

Before deleting --- After deleting

… --- …

m - 2 --- n - 2

m - 1 --- n - 1

m ---- None (because the number has been deleted)

m + 1 --- 1 (because I will count from here next time)

m + 2 ---- 2

… ---- …

There are only n-1 nodes in the new ring. And the nodes numbered m + 1, m + 2, m + 3 before deletion become the nodes numbered 1, 2, 3 after deletion.

Assuming old is the node number before deletion, and new is the number after deleting a node, the relationship between old and new is old = (new + m-1)% n + 1.

In this way, we get the relationship between f(n, m) and f(n-1, m), and f(1, m) = 1. So we can do it in a recursive way. code show as below:

Note: Some people may wonder why it is not old = (new + m)% n? Mainly because the numbering starts from 1, not from 0. If new + m == n, the final calculation result will be old = 0. So old = (new + m-1)% n + 1.

int f(int n, int m){
    if(n == 1)   return n;
    return (f(n - 1, m) + m - 1) % n + 1;
}

Let me go, two lines of code are done, and the time complexity is O(n), and the space complexity is O(1), awesome! So if you want to tell others, I want a line of code to solve Joseph's problem? The answer is no problem, as follows:

int f(int n, int m){
    return n == 1 ? n : (f(n - 1, m) + m - 1) % n + 1;
}

Fuck, after the interviewer asks you to write Joseph questions, you just throw this line of code to it.

to sum up

However, in that written test, I did not do it in a recursive way, but did it in a linked list way,,,,, at that time, I didn’t know it could be done with one line of code,,,, welcome to provide half a line. The way to get the code!

You might like
1. Tencent interview questions: With a binary search tree, why do you need a red-black tree?
2. Why can't you learn recursion? Say goodbye to recursion and talk about some of my experiences.
3. An article to understand how a computer sends data to another computer.
4. How to find the most frequent occurrence from 20/40/80 billion integers with only 2GB of memory Number
5. String matching Boyer-Moore algorithm: How is the search function in the text editor implemented?

Remember an Ali written test: How do I solve the Joseph ring problem with one line of code

Guess you like

Origin blog.51cto.com/15015171/2554967