算法题求解呀,

别卷了啊 2020-03-26 05:58:16
编程题:把1,2,3,4,…,2020这2020个数均匀排成一个大圆圈, 从1开始数,第1个留着,接下来3个(2,3, 4)划掉, 第5个留着,接下来3个(6,7,8)划掉, 一直处理下去。 问:最后剩下哪个数?



今天笔试了一道题,在循环得时候卡壳了,没做出来,哪位大佬有正确解呀。
...全文
600 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_39936465 2020-03-30
  • 打赏
  • 举报
回复

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> list=new ArrayList<Integer>();
		for(int i=1;i<2021;i++)list.add(i);
		while(list.size()>1) {
			for(int i=0;i<list.size();i++) {
				if(i%4!=1) {
					list.remove(i);
				}
			}
		}
		System.out.println(list.get(0));
	}

}
qq_45988227 2020-03-30
  • 打赏
  • 举报
回复
应该是约瑟夫环吧这
nayi_224 2020-03-30
  • 打赏
  • 举报
回复
引用 10 楼 paullbm 的回复:
[quote=引用 6 楼 nayi_224 的回复:] 手写我也挂了。。。
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> list = new LinkedList();
		for(int i = 0; i < 2020; i++) {
			list.add(i);
		}
		
		for(int i = 1, idx = 1; list.size() > 1; i++, idx = idx == list.size() ? 0 : idx) {
			if(i % 4 != 1) 
				list.remove(idx);
			else 
				idx = ++idx;
		}
		System.out.println(list.get(0));
	}
思路不错,不过如果总数比较大的话,运行效率不如递归(每次新建了数组)的方式。 链表的查找效率和数据量是成反比的! 毕竟其在内存空间中的存储地址不是连续性的,而是跳跃性的。 由于数组的地址是连续性的,所以索引效率更高! 另外,程序还有BUG,比如当总数分别为1,5,9,13,29,45,61,125时。。。 当然了,125之后的我就没有去验证了。。。[/quote] 整体串了一位

	public static void test1(int total) {
		LinkedList<Integer> list = new LinkedList();
	    for(int i = 1; i <= total; i++) {
	        list.add(i);
	    }
	    for(int i = 1, idx = 0; list.size() > 1; i++, idx = idx == list.size() ? 0 : idx) {
	        if(i % 4 != 1) 
	        	list.remove(idx);
	        else 
	            idx = ++idx;
	    }
	    System.out.println("val = " + list.get(0));
	}
确实这种写法的效率很低,但是慢的不是链表,而是LinkedList,优化一下后效率会高很多,如果不考虑链表的初始化,效率一定会远高于数组。
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;

public class LinkedListPlus<E> extends LinkedList<E>{
	
	Node<E> first;
	Node<E> last;
	int size = 0;
	
	public boolean add(E e) {
        linkLast(e);
        return true;
    }
	
	void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
        last.next = first;
        first.prev = last;
    }
	
	private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
	
	public IteratorPlus<E> iterator() {
		return new Itr();
	}
	
	public int size() {
        return size;
    }
	
	private class Itr implements IteratorPlus<E> {
		
        int cursor = 0;
        
        private Node<E> thisNode;

        public boolean hasNext() {
            return cursor != size();
        }

        public E next() {
            try {
                int i = cursor;
                E next = thisNode == null ? (thisNode = first).item : (thisNode = thisNode.next).item;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                throw new NoSuchElementException();
            }
        }
        
        public E removeThis() {
        	E v = this.thisNode.item;
        	Node<E> temp = this.thisNode.next;
        	Node<E> prev = this.thisNode.prev;
        	this.thisNode.prev.next = this.thisNode.next;
        	this.thisNode = temp;
        	this.thisNode.prev = prev;
        	size--;
        	//cursor--;
        	return v;
        }

        public void remove() {
        }

        public void resetCursor() {
        	cursor = 0;
        }
    }
	
	public static interface IteratorPlus<E> extends Iterator{
		public void resetCursor();
		public E removeThis();
	}
	
}
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import test.lt20.LinkedListPlus.IteratorPlus;

public class Test12 {

	public static void main(String[] args) {
	    // TODO Auto-generated method stub
		
		int total = 15000000;
		
		
		long time = System.currentTimeMillis();
		fin(total);
	    time = System.currentTimeMillis();
	    System.out.println("--------");
	    test2(total);
	    System.out.println("数组总时间 = " + (System.currentTimeMillis() - time));
	}
	
	public static void test1(int total) {
		LinkedList<Integer> list = new LinkedList();
	    for(int i = 1; i <= total; i++) {
	        list.add(i);
	    }
	    for(int i = 1, idx = 0; list.size() > 1; i++, idx = idx == list.size() ? 0 : idx) {
	        if(i % 4 != 1) 
	        	list.remove(idx);
	        else 
	            idx = ++idx;
	    }
	    System.out.println("val = " + list.get(0));
	}
	
	public static void test2(int total) {
        List<Integer> list = new ArrayList<>();
        long time = System.currentTimeMillis();
        for(int i= 1 ; i<=total;i++){
            list.add(i);
        }
        System.out.println("数组初始化 = " + (System.currentTimeMillis() - time));
        List<Integer> newList = test(list, 0);
        System.out.println("val = " + newList.get(0));
	}
	
    public static List<Integer> test(List<Integer> list,int index){
        List<Integer> newList = new ArrayList<>();
        for (Integer i : list) {
            if(index%4==0){
                newList.add(i);
            }
            index ++;
        }
        //如果新集合为空  则上次集合的最后一位为最后剩下的一位
        if(newList.size()==0){
            newList.add(list.get(list.size()-1));
        }
        if(newList.size()==1){
            return newList;
        }
        return test(newList,index);
    }
    
    public static void fin(int total) {
    	long time = System.currentTimeMillis();
    	LinkedListPlus<Integer> list = new LinkedListPlus<Integer>();
	    for(int i = 1; i <= total; i++) {
	        list.add(i);
	    }
	    System.out.println("链表初始化 = " + (System.currentTimeMillis() - time));
	    IteratorPlus<Integer> it = list.iterator();
	    
	    time = System.currentTimeMillis();
	    
	    boolean flag = it.hasNext();
	    int i = 0;
	    Integer temp = null;
	    if(flag) {
	    	it.next();
		    do {
		    	if(++i % 4 != 1) {
		    		temp = it.removeThis();
		    	}else {
		    		it.next();
		    	}
		    	
		    	if(!(flag = it.hasNext())) {
		    		it.resetCursor();
		    		flag = it.hasNext();
		    	}
		    } while (flag);
	    }
	    
	    System.out.println("val = " + temp);
	    
	    System.out.println("链表筛选  = " + (System.currentTimeMillis() - time));
    }
    
}
链表初始化 = 13883
val = 3222785
链表筛选  = 412
--------
数组初始化 = 1306
val = 3222785
数组总时间 = 8339
还有一种更直观的解法是用队列(Queue),不过效率跟我写那个竟然一样,毕竟底层都是用的一个原理。
import java.util.LinkedList;
import java.util.Queue;

public class Test13 {

	public static void main(String[] args) {
		long time = System.currentTimeMillis();
		doQueue(15000000);
		System.out.println("队列总时间 = " + (System.currentTimeMillis() - time));
	}
	
	public static void doQueue(int total) {
		Queue<Integer> queue = new LinkedList<Integer>();
    	for(int i = 1; i <= total; i++) {
    		queue.add(i);
    	}
    	int i = 0;
    	while(queue.size() > 1) {
    		if(++i % 4 == 1) 
    			queue.add(queue.poll());
    		else 
    			queue.poll();
    	}
    	
    	System.out.println("val : " + queue.peek());
    }
	
}
总结来说,虽然数组的测试速度要更快一些,但是频繁的创建大数组很可能是更糟糕的一件事,如果项目里真的有这种需求,我还是更倾向于使用链表。
paullbm 2020-03-27
  • 打赏
  • 举报
回复
引用 6 楼 nayi_224 的回复:
手写我也挂了。。。
	public static void main(String[] args) {
// TODO Auto-generated method stub
List<Integer> list = new LinkedList();
for(int i = 0; i < 2020; i++) {
list.add(i);
}

for(int i = 1, idx = 1; list.size() > 1; i++, idx = idx == list.size() ? 0 : idx) {
if(i % 4 != 1)
list.remove(idx);
else
idx = ++idx;
}
System.out.println(list.get(0));
}


思路不错,不过如果总数比较大的话,运行效率不如递归(每次新建了数组)的方式。
链表的查找效率和数据量是成反比的!
毕竟其在内存空间中的存储地址不是连续性的,而是跳跃性的。
由于数组的地址是连续性的,所以索引效率更高!

另外,程序还有BUG,比如当总数分别为1,5,9,13,29,45,61,125时。。。
当然了,125之后的我就没有去验证了。。。
nayi_224 2020-03-27
  • 打赏
  • 举报
回复
手写我也挂了。。。
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> list = new LinkedList();
		for(int i = 0; i < 2020; i++) {
			list.add(i);
		}
		
		for(int i = 1, idx = 1; list.size() > 1; i++, idx = idx == list.size() ? 0 : idx) {
			if(i % 4 != 1) 
				list.remove(idx);
			else 
				idx = ++idx;
		}
		System.out.println(list.get(0));
	}
King* 2020-03-27
  • 打赏
  • 举报
回复
这个就跟那个约瑟夫问题基本一样的,循环链表可以实现
月夜轻飞雪 2020-03-27
  • 打赏
  • 举报
回复
双向循环链表。
散着步的码农 2020-03-27
  • 打赏
  • 举报
回复
最开始看这不就是个递归么? 自己写了下发现还真不是那么简单的 - - 花了20分钟 我了去 面试的话就挂了 有做过相关题的话我估计就简单了 不知道大佬们还有没有别的更简单的方法啊
public static void main(String[] args) {
		List<Integer> list = new ArrayList<>();
		for(int i= 1 ; i<=2020;i++){
			list.add(i);
		}
		List<Integer> newList = test(list, 0);
		System.out.println(newList.get(0));
	}
	
	
	public static List<Integer> test(List<Integer> list,int index){
		List<Integer> newList = new ArrayList<>();
		for (Integer i : list) {
			if(index%4==0){
				newList.add(i);
			}
			index ++;
		}
		//如果新集合为空  则上次集合的最后一位为最后剩下的一位
		if(newList.size()==0){
			newList.add(list.get(list.size()-1));
		}
		if(newList.size()==1){
			return newList;
		}
		return test(newList,index);
	}
  • 打赏
  • 举报
回复
就这?? 其实我也懵逼, 这几天做codewars leetcode codinggame 人都傻了 太难了

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧