笔试算法题目,奶牛排队喝水

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 ;
     }
}

转载于:https://www.cnblogs.com/wangsicongde/p/7576890.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值