Sword refers to offer-45-the last remaining number in the circle-java

Questions and tests

package sword045;
/* 题目:0,1,...,n-1 这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

测试样例:

输入: 0,1 , 2, 3, 4

输出: 3
*/

import java.util.List;

public class main {
	
	public static void main(String[] args) {
		int [] testTable = {5,10,15};
		int [] testTable2 = {1,2,3};
		for(int i=0;i<testTable.length;i++){
			test(testTable[i],testTable2[i]);
		}
	}
		 
	private static void test(int ito,int ito2) {
		Solution solution = new Solution();
		int rtn;
		long begin = System.currentTimeMillis();
		System.out.print(ito+"  ");
		System.out.print(ito2);
		System.out.println();
		//开始时打印数组
		
		rtn= solution.lastRemaining(ito,ito2);//执行程序
		long end = System.currentTimeMillis();	
		
		System.out.println("rtn=" );
		System.out.print(rtn);	
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

Solution 1 (success)

Since there is a digital circle in the title, the natural idea is to use a data structure to simulate this circle. Among the commonly used data structures, we can easily think of circular linked lists. We can create a circular linked list with a total of n nodes, and then delete the mth node from this linked list every time

package sword045;


public class Solution {
	public int lastRemaining(int n, int m) {
		if(n == 0 || n==1) {
			return 0;
		}
		ListNode first = new ListNode(0);
		ListNode now = first;
		for(int i=1;i<n;i++) {
			now.next = new ListNode(i);
			now = now.next;
		}
		now.next = first;
		now = first;
		for(int i=0;i<n-1;i++) {
			for(int j = 1;j<m;j++) {
				now = now.next;
			}
			removeNode(now);
		}
		return now.val;
	}
	
	private void removeNode(ListNode node) {
		ListNode next = node.next;
		node.val = next.val;		
		node.next = next.next;
		next.next = null;
	}
	
	
}

Solution 2 (other people's)

Define the function f(n,m), which means deleting the last remaining number of the m-th number from the n numbers 0,1,...,n-1 each time.
Among the n numbers, the first number to be deleted is (m%n)-1, and we denote this number as K. After deleting the first element K, the remaining n-1 numbers are 0 ,1,2,...,k-1,k+1,...,n-1, and the next deletion starts counting from K+1. Then, the next count is actually equivalent to traversing in such a sequence: K+1,...,n-1, 0, 1,..., K-1. This sequence is actually the same as the previous one. The difference is that we have modified its order, but the traversal order is the same when deleting elements. Therefore, the remaining numbers after several deletions should be the same as the previous sequence. We delete the m-th digit in the last sequence and record the remaining digits as f'(n-1,m). As for why it is recorded as f'(n-1,m), you will understand later. So now we can at least be sure that f(n,m)=f'(n-1,m).

Let's look at this sequence again: k+1,...,n-1,0,1,...,k-1. We map this sequence, and the result of the mapping is a sequence from 0 to n-2:
       k+1 -> 0
       k+2 -> 1
              ......
       n-1 -> nk-2
       0- > nk-1
       1 -> nk
              ......
       k-1 -> n-2
    f'(n-1,m) f(n-1,m)
we define the mapping as p, then p(x) = (xk-1)%n. It means that if the number before the mapping is x, then the number after the mapping is (xk-1)%n. The inverse of this mapping is p-1(x)=(x+k+1)%n. Since you want to master this method, you must understand it thoroughly. Let me prove it with me below:

Proof:
Let y = p(x), that is, y = (xk-1)%n,
then y = (xk-1) +t1n, t1 is an integer, and 0<= y <n  
<---> x = y-t1n + k + 1
<----> x = (y+k+1) + t2n, that is, y = (x+k+1) + tn, so p-1(x) = (x+k +1) %n
proof is complete.

Now, we find that the n-1 numbers after the mapping are the same as the original n numbers in form? Just look at one less number n-1. Then, for the n-1 numbers 0, 1,..., n-2, arrange them in a circle, and delete the m-th number each time from the number 0. Can the remaining numbers be expressed as f(n -1,m)?! Now, have you discovered why we defined the sequence as f'(n-1,m) before? This is to establish a connection between two deletions! That is to say, the original n elements, after deleting the first element k, the initial sequence is arguably disrupted and there are no rules; but we rearrange the sequence into the form of the initial sequence through a mapping relationship. In this way, as long as we find such a mapping relationship and find the functional relationship (iteration law) between the two operations, the problem will be transformed into a recursive problem. The exit of the recursive problem is very easy to determine. When n=1, the sequence has only one element: 0, f(1,m) is this 0!
Now that there is a mapping relationship, let's find the relationship between two iterative operations, that is, how to find f(n,m) from f(n-1,m).

Solution:
Because f(n,m) = f'(n-1,m), and f'(n-1,m) = (f(n-1,m)+k+1)%n, so f (n,m) = (f(n-1,m)+k+1)%n. And because k = (m%n)-1, bringing in f(n,m) = (f(n-1,m)+k+1)%n, we get: f(n,m) = (f( n-1,m)+m)%n.
Therefore, when n=1, f(n,m) = 0
When n>1, f(n,m) = [f(n-1,m)+m]%n

With this recurrence relationship, is it possible to write code? You can use recursion from top to bottom, or iterate from bottom to top. Recursion obviously does not have the problem of resolving sub-problems here, but there will be a lot of stack operations, so it is better to use iterative methods directly. As for the source code of the iterative method, it has been given above. int last = 0; is the value of f(1,m) when n=1; the following for loop is to solve the value of f(n,m) from the bottom up.
This idea is very complicated, but the code is particularly concise, and the main time is spent analyzing and deriving formulas. The time complexity of this method is O(n), and the space complexity is O(1). Both the time complexity and the space complexity are better than the first method.

public static int lastRemaining_2(int n,int m){
        if(n<1||m<1) return -1;
        int last = 0;
        for(int i=2;i<=n;i++){
            last = (last+m)%i;
        }
        return last;
    }

 

Guess you like

Origin blog.csdn.net/xushiyu1996818/article/details/112461340
Recommended