剑指offer——算法【数组】

题目描述

  在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数

解题:

二维数组是有序的,从左下角来看,向上数字递减,向右数字递增。
因此从左下角开始查找,

  • 当要查找数字当前数字大时,右移;
  • 当要查找数字比当前数字小时,上移;
  • 如果出了边界,则说明二维数组中不存在该整数。

代码如下:

 1 public class Solution {
 2     public boolean Find(int [][]array,int target){
 3 
 4         int len = array.length-1;//
 5         int i = 0;//
 6 
 7         while((len >= 0 )&&(i < array[0].length )){
 8             if (target < array[len][i]){
 9                 len = len-1;
10             }
11             else if (target > array[len][i]){
12                 i = i+1;
13             }else {
14                 System.out.println("已找到,在第"+(len+1)+"行,第"+(i+1)+"列");
15                 return true;
16             }
17         }
18         System.out.println("没有找到");
19         return false;
20     }
21     public static void main(String[] args){
22         int [][]array={{0,1,2,3,4},{1,2,4,4,5}};
23         int target = 5;
24         Solution a = new Solution();
25         a.Find(array,target);
26     }
27 }
View Code

2.旋转数组的最小数字

题目描述

  把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

解题:

采用二分查找法:

需要考虑三种情况:

  分别是:

    1.最小数字在左边。延展来说就是 “array[mid] < array[high] ”的情况。出现这种情况的array类似[2,3,4,5,6,7,7],此时最小数字一定就是array[mid]或者在mid的左边。因为右边必然都是递增的。解决办法:high = mid

    2.最小数字在右边。延展来说就是“ array[mid] > array[high] ”的情况。出现这种情况的array类似[3,4,5,6,7,1,2],此时最小数字一定是在mid的右边。解决办法:low = mid + 1;

    3.最小数字不知道在哪边。这种情况的array类似[1,1,1,1,0,1],此时最小数字不好判断是在哪边。所以只好一个一个的试。所以二分法在一定的条件下也会成为O(n)。解决办法:high = high -1;

以下代码:

 1 public class demo_2 {
 2     public int minNumberInRotateArray(int [] array) {
 3         int len = array.length;//数组长度
 4         if (len == 0 ){
 5             return 0;
 6         }
 7         int low = 0,high = len-1;
 8         while(low<high) {
 9             int mid = low + (high - low) / 2;//这里是防止溢出,等同于 int mid = (low+high)/2
10             if (array[mid] > array[high]) {
11                 low = mid + 1;
12             } else if (array[mid] == array[high]) {
13                 high = high - 1;
14             } else {
15                 high = mid;
16             }
17         }
18         return array[low];
19     }
20     public static void main(String[] args){
21         int []array={3,4,5,1,2};
22         demo_2 a = new demo_2();
23         System.out.println(a.minNumberInRotateArray(array));
24     }
25 }
View Code

3.调整数组顺序使奇数位于偶数前面

题目描述

  输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

解题

  利用冒泡排序将数组改变。如果当前值为偶数,后一个值为奇数,则两个数对换位置。

代码如下:

 1 public class demo_3 {
 2     public void reOrderArray(int [] array) {
 3 
 4         for( int i = 0;i<array.length ;i++){
 5             for (int j = 0;j<array.length-1;j++){
 6                 if (array[j]%2 == 0 && array[j+1]%2 ==1){//先偶后奇
 7                     int temp = array[j+1];
 8                     array[j+1] = array[j];
 9                     array[j] = temp;
10                 }
11             }
12         }
13         for(int i:array)//打印出最终的数组
14             System.out.print(" "+i);
15     }
16     public static void main(String[] args){
17         int [] array = {1,2,3,4,5,6,7};
18         demo_3 a = new demo_3();
19         a.reOrderArray(array);
20     }
21 }
View Code

还有一种解法是利用空间换时间,就直接用新的数组分别储存奇数和偶数,最后拼在一起就行了。

   用Vector,Vector是通过封装数组实现的,大小动态的,同时线程安全的。

  Vector 元素增加时,size可变大,而且元素可删除,只能存放Object

  array数组,固定大小,且创建时就需指定,可放Object和基本数据类型。

  

 1     public void reOrderArray2(int[] array) {
 2 
 3         Vector<Integer> odd = new Vector<Integer>();
 4         Vector<Integer> even = new Vector<Integer>();
 5 
 6         for (int i = 0; i < array.length; i++) {
 7             if (array[i] % 2 == 0) {
 8                 even.add(array[i]);
 9             } else {
10                 odd.add(array[i]);
11             }
12         }
13         odd.addAll(even);
14         System.out.println(odd);
15   
16     }
17         public static void main (String[] args) {
18             int[] array = {1, 2, 3, 4, 5, 6, 7};
19             demo_3 a = new demo_3();
20             a.reOrderArray2(array);
21         }
View Code

4.顺时针打印矩阵

 题目描述:

  输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

解题:
  顺时针打印就是按圈数循环打印,一圈包含两行或者两列,在打印的时候会出现某一圈中只包含一行,要判断从左向右打印和从右向左打印的时候是否会出现重复打印,同样只包含一列时,要判断从上向下打印和从下向上打印的时候是否会出现重复打印的情况。

代码如下:

 1 import java.util.ArrayList;
 2 
 3 public class demo_4 {
 4 
 5     public ArrayList<Integer> printMatrix(int [][] matrix) {
 6 
 7         int row = matrix.length;//
 8         int col = matrix[0].length;//
 9 
10         ArrayList<Integer> res = new ArrayList<>();//定义一个数组储存
11 
12         if (row == 0 && col ==0){//空数组
13             return res;
14         }
15 
16         int top = 0, buttom = row-1,left = 0,right = col -1;
17         while(top<=buttom && left<=right){
18             for (int i = left; i <= right; i++){//上:从左到右
19                 res.add(matrix[top][i]);
20             }
21             for (int i = top+1;i <= buttom;i++){//右:从上到下
22                 res.add(matrix[i][right]);
23             }
24             //防止单行情况
25             if(top !=buttom) {
26                 for (int i = right-1; i >= left; i--) {//下:从右到左
27                     res.add(matrix[buttom][i]);
28                 }
29             }
30             //防止单列情况
31             if (left !=right) {
32                 for (int i = buttom - 1; i > top; i--) {//左:从下到上,注意这里不能等于top
33                     res.add(matrix[i][left]);
34                 }
35             }
36             left++;
37             right--;
38             top++;
39             buttom--;
40         }
41       return res;
42     }
43             public static void main (String[] args) {
44            int [] []array = {{1,2,3},{8,9,4},{7,6,5}};
45             demo_4 a = new demo_4();
46             System.out.println(a.printMatrix(array));
47         }
48 }
View Code

5.数组中出现次数超过一半的数字

 题目描述:

  数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

解题

  先排序,后取中间数比较。如果某个数字出现次数超过数组的长度的一半,则一定会在数组中间的位置。所以我们取出排序后中间位置的数,统计一下它的出现次数是否大于数组长度的一半;

代码如下

 1 import java.util.Arrays;
 2 public class demo_5 {
 3     public int MoreThanHalfNum_Solution(int [] array) {
 4         Arrays.sort(array);
 5         int count=0;
 6 
 7         for(int i=0;i<array.length;i++){
 8             if(array[i]==array[array.length/2]){
 9                 count++;
10             }
11         }
12         if(count>array.length/2){
13             return array[array.length/2];
14         }else{
15             return 0;
16         }
17 
18     }
19     public static void main(String[] args){
20         int[] array = {1, 2, 3, 4, 2,2,2,2,2,2,2};
21         demo_5 a = new demo_5();
22         System.out.println(a.MoreThanHalfNum_Solution(array));
23     }
24 }
View Code

 

 6.最小的K个数

题目描述:

  输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

解题:
  先对数组排序,再取前K个

代码如下:

 1 import java.util.ArrayList;
 2 import java.util.Arrays;
 3 
 4 public class demo_6 {
 5 
 6     public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
 7         ArrayList<Integer> res = new ArrayList<Integer>();
 8         if(input == null || k ==0 || k > input.length)
 9             return res;
10         Arrays.sort(input);
11         for(int i=0; i<k; i++)
12             res.add(input[i]);
13         return res;
14     }
15      public static void main(String[] args){
16         int i = 5;
17         int [] array ={1,1,2,3,4,5,6,7};
18         demo_6 a = new demo_6();
19         System.out.println(a.GetLeastNumbers_Solution(array,i));
20      }
21 }
View Code

7.连续子数组的最大和

题目描述:

  HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

解题:

  这道题我也愣了一会才看懂题目的意思。其实就是连续子序列的最大和问题。

 代码如下:

 1 public class demo_7 {
 2     public int FindGreatestSumOfSubArray(int[] array) {
 3 
 4         if (array.length == 0)
 5             return 0;
 6 
 7         int a = array[0];//记录当前值
 8         int max = array[0];
 9         for (int i = 1; i < array.length; i++) {
10             if (a > 0) {
11                 a = a + array[i];
12             } else {
13                 a = array[i];
14             }
15             if (max < a) {
16                 max = a;
17             }
18         }
19         return max;
20     }
21     public static void main(String[] args){
22 
23         int [] array={6,-3,-2,7,-15,1,2,2};
24         demo_7 a = new demo_7();
25         System.out.println(a.FindGreatestSumOfSubArray(array));
26 
27     }
28 }
View Code

8.把数组排成最小的数

题目描述:

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

解题:

  这题看了有一会了。算是比较有技巧的一题吧。这里想着用排序能不能就直接搞定,然后发现不行!怎么不行呢,例如,3和32, 3<32,所以3排在32的前面,但是332>323。所以3又应该排在32的后面。

   所以在这里自定义一个比较大小的函数,比较两个字符串s1, s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面,所以按这个规则,先将整型数组转换成String数组,然后将String数组排序,最后将排好序的字符串数组拼接出来。关键就是制定排序规则。

代码如下:

import java.util.Arrays;
import java.util.Comparator;

public class demo_8 {
    public String PrintMinNumber(int [] number){
        if(number == null || number.length == 0){
            return null;
        }
        int len =number.length;
        String[] str = new String[len];
        StringBuilder sb = new StringBuilder();
        for (int i=0;i<len;i++){
            str[i] = String.valueOf(number[i]);
        }
        Arrays.sort(str,new Comparator<String>(){
            public int compare(String s1, String s2) {
                String c1 = s1 + s2;
                String c2 = s2 + s1;
                return c1.compareTo(c2);
            }
        });
        for(int i = 0; i < len; i++){
            sb.append(str[i]);
        }
        return sb.toString();
    }
    
    public static void main(String[] args){
        int [] number = {3,2,22,33,32};
        demo_8 a = new demo_8();
        System.out.println(a.PrintMinNumber(number));

    }
}
View Code

9.数组中的逆序对

题目描述:

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

更多待续......

相关推荐