剑指offer31-35

31把数组排成最小的数

  输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

 

比较两个字符串s1, s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面,所以按这个规则,s2就应该排在s1前面

public class PrintMinNumber_31 {

    public static void main(String[] args) {
        PrintMinNumber_31 min = new PrintMinNumber_31();
        int[] num = {3,32,321};
        String res = min.PrintMinNumber(num);
        System.out.println(res);
    }
    public String PrintMinNumber(int[] numbers) {
        for(int i = 0; i < numbers.length; i++) {
            for(int j = i + 1; j < numbers.length; j++) {
                int sum1 = Integer.valueOf(numbers[i]+""+numbers[j]);
                int sum2 = Integer.valueOf(numbers[j]+""+numbers[i]);
                if(sum1 > sum2) {
                    int temp = numbers[i];
                    numbers[i] = numbers[j];
                    numbers[j] = temp;
                }
            }
        }
        String str = "";
        for(int i = 0; i < numbers.length; i++) {
             str += numbers[i]+"";
        }
        return str;
    }

}

32丑数

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。


丑数能够分解成2^x3^y5^z,
所以只需要把得到的丑数不断地乘以2、3、5之后并放入他们应该放置的位置即可,
而此题的难点就在于如何有序的放在合适的位置。
1乘以 (2、3、5)=2、3、5;2乘以(2、3、5)=4、6、10;3乘以(2、3、5)=6,9,15;5乘以(2、3、5)=10、15、25;
从这里我们可以看到如果不加策略地添加丑数是会有重复并且无序,
而在2x,3y,5z中,如果x=y=z那么最小丑数一定是乘以2的,但关键是有可能存在x》y》z的情况,所以我们要维持三个指针来记录当前乘以2、乘以3、乘以5的最小值,然后当其被选为新的最小值后,要把相应的指针+1;因为这个指针会逐渐遍历整个数组,因此最终数组中的每一个值都会被乘以2、乘以3、乘以5,也就是实现了我们最开始的想法,只不过不是同时成乘以2、3、5,而是在需要的时候乘以2、3、5.

public class GetUglyNumber_32 {

    public static void main(String[] args) {
        GetUglyNumber_32 ugly = new GetUglyNumber_32();
        int index = 7;
        int res = ugly.GetUglyNumber_Solution(index);
        System.out.println(res);
    }
    public int GetUglyNumber_Solution(int index) {
        int[] result = new int[index];
        int p2 = 0; int p3 = 0; int p5 = 0;
        result[0] = 1;
        for(int i = 1; i < index; i++) {
            result[i] = Math.min(result[p2]*2,Math.min(result[p3]*3, result[p5]*5));
            if(result[i] == result[p2]*2)p2++;
            if(result[i] == result[p3]*3)p3++;
            if(result[i] == result[p5]*5)p5++;
        }
        return result[index-1];
    }

}

33第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

public class FirstNotRepeatingChar_33 {

    public static void main(String[] args) {
        FirstNotRepeatingChar_33 first = new FirstNotRepeatingChar_33();
        String s = "abcbcjAa";
        int res = first.FirstNotRepeatingChar(s);
        System.out.println(res);
    }

    public int FirstNotRepeatingChar(String s) {
        if (s.length() == 0)
            return -1;
        int[] count = new int[123];
        for(int i = 0; i < s.length(); i++) {
            count[s.charAt(i)]++;
        }
        for(int i = 0; i < s.length(); i++) {
            if(count[s.charAt(i)] == 1) {
                return i;
            }
        }
        return -1;
    }

}

 35 数组中的逆序对  

  在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

  在归并排序的过程中 后一个数组的数如小于前一个数组的数,则一定能够构成逆序对且逆序对的数目可计算,因为待归并的两个数组提前已经归并排序过,所以不会出现像前面那样少统计或者多统计的情况出现。
思路:[A,B]中的逆序对=[A]的逆序对+[B]中的逆序对+将A,B混排在一起的逆序对
而将A,B混排在一起的逆序对求解看下面:

public class InversePairs_35 {

    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,6,7,0};
        InversePairs_35 result = new InversePairs_35();
        int res = result.InversePairs2(array);
        System.out.println(res);
        
    }
    //暴力法  时间复杂度:O(N^2)  空间复杂度:O(1)
    public int InversePairs(int [] array) {
        int kmod = 1000000007;
          int ret = 0;
      int n = array.length;
      for (int i = 0; i < n; ++i) {
          for (int j = i + 1; j < n; ++j) {
              if (array[i] > array[j]) {
                  ret += 1;
                  ret %= kmod;
              }
          }
      }

      return ret;
  }
    //归并排序  时间复杂度:O(NlogN)
    //空间复杂度:O(N)
    public int InversePairs2(int [] array) {
        MergeSort(array, 0, array.length-1);
        return cnt;
    }
    private int cnt;
    private void MergeSort(int[] array, int start, int end){
        if(start>=end)return;
        int mid = (start+end)/2;
        MergeSort(array, start, mid);
        MergeSort(array, mid+1, end);
        MergeOne(array, start, mid, end);
    }
    private void MergeOne(int[] array, int start, int mid, int end){
        int[] temp = new int[end-start+1];
        int k=0,i=start,j=mid+1;
        while(i<=mid && j<= end){
//如果前面的元素小于后面的不能构成逆序对
            if(array[i] <= array[j])
                temp[k++] = array[i++];
            else{
//如果前面的元素大于后面的,那么在前面元素之后的元素都能和后面的元素构成逆序对
                temp[k++] = array[j++];
                cnt = (cnt + (mid-i+1))%1000000007;
            }
        }
        while(i<= mid)
            temp[k++] = array[i++];
        while(j<=end)
            temp[k++] = array[j++];
        for(int l=0; l<k; l++){
            array[start+l] = temp[l];
        }
    }
    

}

 

posted @ 2020-06-02 17:44  我们村里的小花儿  阅读(185)  评论(0编辑  收藏  举报