1. 程式人生 > >筆試算法題目,奶牛排隊喝水

筆試算法題目,奶牛排隊喝水

can tmp tin start problem clas 描述 int start map

題目:

題目描述
有N(1≤N≤1000)頭奶牛,它們都被標上一個優先等級編號:1,2或3。用來表示它們喝水時的優先次序,編號為l的最優先,編號為2的其次,編號為3的最後。每天奶牛開始時排成一行,但總是很亂,需要你把它們重新排成編號為1的奶牛在最前面,編號為2的其次,編號為3的奶牛在最後。你能計算出最少需要多少的交換次序來完成這次重排嗎?

輸入
第1行:1個整數N;
第2至N+I行:第i+l行有一個整數表示開始隊列中第i頭奶牛的編號。

輸出
1行,只一個整數,表示最少需要交換次數。

樣例輸入

9
2 2 1 3 3 3 2 3 1

樣例輸出

4

思路:在讀入的時候記錄一下1 2 3三個數的數目,然後就可以確定排完序之後他們的界限,然後從1的區域開始掃,掃到2就優先去2的區域找,找不到就去3的區域找,掃到3同理,這樣就能保證每一次交換都是最優的,將2區域掃完之後也就完成了所有的交換。如果在1的區掃描到4則同樣優先到4的區尋找1,找不到的話從“1的區和4的區”的之外所有區進行尋找,最後交換。



import java.util.*;

/**
 * Created by Daxin on 2017/8/19.
 * <p/>
 * 奶牛排隊飲水問題
 * 輸入:n牛的數目,然後n個整數表示牛的序號
 * 輸出:輸出交換最少次數
 * <p/>
 * 例如一個測試用例:9<br>
 * 2,2,1,3,3,3,2,3,1<br>
 * 輸出:4
 *
 *在線題目地址:http://www.hustoj.com/oj/problem.php?id=1056
 *
 *
 */
public class CattleSortWater {

    public static void main(String[] args) {

//        int[] nums = {2, 2, 1, 3, 3, 3, 2, 3, 1};

        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = cin.nextInt();
        }


        System.out.println(solve(nums));
//        System.out.println(Arrays.toString(nums));


    }


    public static int solve(int[] nums) {
        int result = 0;
        Map<Integer, Integer> wcount = new TreeMap<>();
        Map<Integer, Integer> range = new TreeMap<>();
        for (int num : nums) {
            Integer tmp = wcount.get(num);
            wcount.put(num, tmp == null ? 1 : tmp + 1);
        }

        Set<Integer> set = wcount.keySet();
        int pre = 0;
        for (int i : set) {
            int tmp = wcount.get(i) + pre;
            range.put(i, tmp);
            pre = tmp;
        }


        for (int num : set) {

            int times = wcount.get(num);
            int ran = range.get(num);
            for (int i = ran - 1, t = times; t > 0; t--, i--) {

                if (nums[i] != num) {
                    int r = get(nums, range.get(nums[i]), wcount.get(nums[i]), num);
                    if (r != -1) { //在nums[i] 區間中尋找到了num

                        int tmp = nums[r];
                        nums[r] = nums[i];
                        nums[i] = tmp;
                        result++;

                    } else {// 在希望區間沒有找到,進行余下遇見全掃描
                        int rr = getRange(nums, ran, num,range.get(nums[i])-wcount.get(nums[i]),range.get(nums[i]));
                        if (rr != -1) {

                            int tmp = nums[rr];
                            nums[rr] = nums[i];
                            nums[i] = tmp;
                            result++;
                        }

                    }

                }


            }


        }


        return result;
    }

    /**
     *
     * @param nums 數組
     * @param range 結束的下標
     * @param times 出現的次數,range-times就是起始下標
     * @param expect 希望查找的希望值
     * @return
     */
    public static int get(int[] nums, int range, int times, int expect) {

        for (int i = range - 1, t = times; t > 0; t--, i--) {
            if (nums[i] == expect) {
                return i;
            }

        }
        return -1;
    }

    /**
     *
     * @param nums 數組
     * @param start 查找的起始位置,結束位置是數組的結束
     * @param expect 期望尋找到的值
     * @param exceptStart 排除區域的起始下標
     * @param exceptEnd 排除區域的結束下標
     * @return 返回下標
     */
    public static int getRange(int[] nums, int start, int expect,int exceptStart,int exceptEnd) {

        for (; start < nums.length; start++) {
            if(start>=exceptStart&&start<exceptEnd)
                continue;
            if (nums[start] == expect) {
                return start;
            }

        }
        return -1;
    }


}

  

在線題目地址:http://www.hustoj.com/oj/problem.php?id=1056

筆試算法題目,奶牛排隊喝水