題目描述:
0, 1, …, n-1這n個數字(n>0)排成一個圓圈,從數字0開始每次從這個圓圈裏刪除第m個數字。求出這個圓圈裏剩下的最後一個數字。
樣例:
輸入:n=5 , m=3
輸出:3
分析:
將這n個數字存入列表中,通過舉例可以得出第一次刪除的數字下標爲(m-1)%n記爲c,
之後每一次刪除的數字下標均爲(c+m-1)%list.size()
public int LastRemaining_Solution(int n, int m) {
if(n==0||m==0)
return -1;
List<Integer> list=new ArrayList<>();
for(int i=0;i<n;i++)
list.add(i);
int c=(m-1)%n;
while(list.size()!=1) {
list.remove(c);
c=(c+m-1)%list.size();
}
return list.get(0);
}
環形單鏈表的約瑟夫問題
題目描述
一個環形單向鏈表的頭結點head和報數的值m。
返回:最後生存下來的節點,且這個節點自己組成環形單向鏈表,其他節點都刪掉。
題解
普通解法:
- 1、如果鏈表爲空或者鏈表節點數爲1,或者m的值小於1,則不用調整就直接返回
- 2、在環形鏈表中遍歷每個節點,不斷轉圈,不斷讓每個節點報數。
- 3、當報數達到m時,就刪除當前報數的節點
- 4、刪除節點後,別忘了還要把剩下的節點繼續連成環狀,繼續轉圈報數,繼續刪除
- 5、不停地刪除,直到環形鏈表中只剩一個節點,過程結束。
- 6、每刪除一個節點,都需要遍歷m次,一共需要刪除的節點數爲n-1,所以這種方法的時間複雜度爲O(nm)
public static Node killNode(Node head,int m) {
if(head==null||head.next==head||m<1) {
return head;
}
Node last=head;
//找到next節點指向頭結點的節點
while(last.next!=head) {
last=last.next;
}
int count=0;
//當next節點指向自己時結束
while(head!=last) {
if(++count==m) {
last.next=head.next;
count=0;
}else {
last=last.next;
}
head=last.next;
}
return head;
}
O(N)的解法
- 1、統計鏈表中節點的個數,將每個節點添加到列表中保存
- 2、第一次刪除的節點下標爲(m-1)%節點個數
- 3、下一次刪除的節點下標爲(上一次刪除的節點的下標+m-1)%當前節點個數
- 4、直到列表長度爲1時停止
public static Node killNode1(Node head,int m) {
if(head==null||head.next==head||m<1) {
return head;
}
List<Node> list=new ArrayList();
Node last=head;
list.add(head);
//找到next節點指向頭結點的節點
while(last.next!=head) {
last=last.next;
list.add(last);
}
int index=(m-1)%list.size();
while(list.size()!=1) {
list.remove(index);
index=(index+m-1)%list.size();
}
Node n=list.get(0);
n.next=n;
return n;
}