• 小孩排队问题


    标签: 算法


    初始问题:幼儿园小孩排成一行,但是男孩和女孩相邻会冲突,现在你是老师,每次只能调换相邻两个小孩的位置,要使男女冲突最少,至少要调换多少次?

    输入情况: 用形如'BBBGGBB'的一个字符串表示队伍,'B'表示男孩,'G'表示女孩。

    输入情况:最少的调换次数。

      目标是使男女冲突最少,可以理解为把男孩和女孩分开两边,左边全站男孩,右边全站女孩(或者左边全站女孩,右边全站男孩),那就只有中间的一个男孩一个女孩相邻了,显然这样冲突最少。

    例如:'BBGBG' 变成 'BBBGG' 或者 ' GGBBB'
    

    思路一:每次只能调换相邻两个小孩的位置,这个问题类似与冒泡排序,即每次调换两个冲突的小孩的位置,那么每次循环下来,就把一个小孩调换(移动)到最左边或者最右边,两重循环即可把所有孩子调换好,需要调换时使用计数器加一记录即可。

    // 从右往左冒泡
    // @s 小孩队列
    // @move 该移动的小孩,'B'为男孩,'G'为女孩
    public static int bubbleCount(char[] s, char move) {
    	int count = 0;
    	for (int i = 0; i < s.length - 1; i++) {
    		for (int j = s.length - 1; j > i; j--) {
    		    // 若相邻两小孩性别不同,需要调换
    			if (s[j] == move && s[j] != s[j - 1]) {
    				swap(s[j], s[j - 1]);
    				count++;
    			}
    		}
    	}
    	return count;
    }
    

      这种方法使用了冒泡排序算法,复杂度为(O(n^2)),能算出移动男孩或者移动女孩的次数,且修改了原队列的值。

      要注意,只移动男孩或只移动女孩,有时并不是最优解。例如队列'BBBBBGB'时,如果移动男孩(这里统一指往左边移动),只需要将最右边的男孩往左移动1次。但移动的是女孩时,则需要调换5次。即实际上,调换男孩是调换次数最少的换法。所以要考虑这两种情况的最小值,即min(bubbleCount(s, 'B'), bubbleCount(s, 'G')

    思路二:不改变原队列的值,只记录某个小孩右边的异性个数,该个数即该小孩需要调换(移动)的次数,问题是求得所有小孩移动次数的总和。

    // 从左往右计数
    // @s 小孩队列
    // @move 该移动的小孩,'B'为男孩,'G'为女孩
    public static int count(char[] s, char move) {
    	int count = 0;
    	for (int i = 0; i < s.length; i++) {
    		if (s[i] == move) 
    			for (int j = i + 1; j < s.length; j++) 
    				if (s[j] != move) count++;
    		return count;
    	}
    }
    

      这个方法循环计算了每个待移动的小孩右边的异性个数,复杂度为(O(n^2))。有没有更加好的方法?我们观察到,从左到右计数时,异性的个数其实是重复计数的,所以我们可以使用一个变量存储起来,这时只需要循环一次即可解决问题,复杂度为(O(n))

    // 从左往右计数
    // @s 小孩队列
    // @move 该移动的小孩,'B'为男孩,'G'为女孩
    public static int count(char[] s, char move) {
    	int count = 0;
    	// 不需移动的小孩个数
    	int notMoveNum = 0;
    	for (int i = 0; i < s.length; i++) {
    		if (s[i] == move)
    			count += notMoveNum;
    		else
    			notMoveNum++;
    	}
    	return count;
    }
    

      实际上,这个方法记录的是某个小孩左边的异性个数。要记录右边的异性个数,只需要把循环条件反过来即可。
      和上面冒泡算法的情况相同,最后要从移动男孩还是移动女孩两种情况中,选出移动次数最少的一种,即min(count(s, 'B'), count(s, 'G')

  • 相关阅读:
    我爱淘冲刺阶段站立会议每天任务2
    我爱淘冲刺阶段站立会议每天任务1
    大道至简-灵活的软件工程
    大道至简-实现,才是目的
    冲刺第二阶段工作总结06
    课堂练习-最低价购书方案
    构建之法阅读笔记04
    冲刺第二阶段工作总结05
    冲刺第二阶段工作总结04
    冲刺第二阶段工作总结03
  • 原文地址:https://www.cnblogs.com/banyu/p/6622272.html
Copyright © 2020-2023  润新知