帮我对象做了很长时间的毕业设计,关于这个每日一算法在这段时间没有坚持下来,十分惭愧。去年到今年的几个月给她做了一个毕设的小项目,是一个关于人脸活体验证身份认证系统,我会在另一个版块给大家慢慢发一些关于其中的代码(因为她还没有答辩完,不能公开所有的代码),同时巩固自己的学习。
好了,开始今天每日一算法的总结:
题目:
关于著名的约瑟夫问题是这样的:在古罗马时期,罗马人占领乔塔帕特后,39个犹太人躲到了一个洞中,他们决定宁愿死也不要让敌人抓到,于是决定了一个自杀方式,39个人排成一个首尾相连的圆圈,由第一个人报数,报数到第3个的人就自杀,然后再由下一个人开始重新报1,报数到3的人再自杀,依次这样下去,直到只剩下最后一个人,那个人可以自己选择生死。现在请用单向链表完成该过程的表示。
分析:
输入:一个环形单向链表的头节点head和报数的值m。
返回:最后生存下来的节点
要求:
如果链表节点数为N,想要在时间复杂度为O(N)完成原问题,应该如何实现?
普通解决方法:
1. 如果链表为空或者链表节点数为1,或者m的值小于1,则不用调整就直接返回了;
2. 在环形链表中遍历每个节点,不断转圈,不断让每个节点报数;
3. 当报数到达m时,就删除当前的报数节点;
4. 删除节点货,把上一个节点指向删除节点的下一节点。继续转圈报数,继续删除。
5. 不停的删除,直到节点只剩下一个节点,过程结束。
具体代码如下:
Node.java
package algorithm_13;
public class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
algorithm_13.java
package algorithm_13;
public class algorithm_13 {
public static Node josephusKill(Node head, int m){
if(head == null || head.next == head || m < 1){
return head;
}
Node last = head;
while(last.next != head){
last = last.next;
}
int count = 0;
while(head != last){
if(++count == m){
last.next = head.next;
count = 0;
}
else{
last = last.next;
}
head = last.next;
}
return head;
}
public static Node init(Node head){
Node start = head;
for (int i = 2; i < 3; i++){
head.next = new Node(i);
head = head.next;
}
head.next = start;
return head;
}
public static void print(Node head){
Node cur = head;
do {
System.out.print(cur.value + " ");
cur = cur.next;
}
while (cur != null && cur != head) ;
System.out.print(" \n");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Node test = new Node(1);
init(test);
System.out.println("Ring linked list: ");
print(test);
Node res = josephusKill(test, 3);
System.out.println("Last living node: ");
print(res);
}
}
结果如下:
Double linked list:
1 2
Last living node:
2
*****注意:*******
普通的解法在实现上每次删除掉一个节点都要遍历m次,一共要删除n-1个节点,所以此方法的时间复杂度了O(n*m)。
*******************