数据结构习题篇----数组

1.数组排序

class Solution {
    public int[] sortArray(int[] nums) {
        //冒泡排序 
        // for(int i = 0;i < nums.length-1;i++){
        //     for(int j = 0;j < nums.length-1-i;j++){
        //         if(nums[j] > nums[j+1]){
        //             int temp = nums[j];
        //             nums[j] = nums[j+1];
        //             nums[j+1] = temp;
        //         }
        //     }
        // }

        //插入排序
        // for(int i = 1;i<nums.length;i++){
        //     int insertVal = nums[i];
        //     int insertIndex = i-1;
        //     while(insertIndex >=0 &&insertVal < nums[insertIndex]){
        //         nums[insertIndex+1] = nums[insertIndex];
        //         insertIndex--;
        //     }
        //     nums[insertIndex+1] = insertVal;
        // }

        //选择排序
        // for(int i = 0;i < nums.length-1;i++){
        //     int minIndex = i;
        //     int min = nums[i];
        //     for(int j = i+1;j < nums.length;j++){
        //         if(min > nums[j]){
        //             min = nums[j];
        //             minIndex = j;
        //         }
        //     }
        //     if(minIndex != i){
        //         nums[minIndex] = nums[i];
        //         nums[i] = min;
        //     }
        // }

        //希尔排序
        // for(int gap = nums.length/2;gap > 0;gap /= 2){
        //     for(int i = gap;i < nums.length;i++){
        //         for(int j = i;j >= gap;j -= gap){
        //             if(nums[j-gap] > nums[j]){
        //                 int temp = nums[j];
        //                 nums[j] = nums[j-gap];
        //                 nums[j-gap] = temp;
        //             }else{
        //                 break;
        //             }
        //         }
        //     }
        // }
        //return nums;

         通过该题练习数组排序的几种算法。

        低级排序:冒泡排序,插入排序,选择排序。

        高级排序:希尔排序,归并排序,快速排序,基数排序(桶排序)。

2.找出数组中重复的数字

         解法一:先排序,后遍历数组(最麻烦的操作)

    public int findRepeatNumber(int[] nums) {
        //先排序,后找重复数字
        // for(int N = nums.length/2;N > 0;N /= 2){
        //     for(int i = N;i <nums.length;i++){
        //         for(int j = i-N;j >=0;j--){
        //             if(nums[j] > nums[j+N]){
        //                 int temp = nums[j+N];
        //                 nums[j+N] = nums[j];
        //                 nums[j] = temp;
        //             }else{
        //                 break;
        //             }
        //         }
        //     }
        // }
        // for(int i = 0;i<nums.length-1;i++){
        //     if(nums[i] == nums[i+1]){
        //         return nums[i];
        //     }
        // }
        // return -1;
    }

        解法二:遍历数组,由于只需要找出数组中任意一个重复的数字,因此遍历数组,遇到重复的数字即返回。为了判断一个数字是否重复遇到,使用集合存储已经遇到的数字,如果遇到的一个数字已经在集合中,则当前的数字是重复数字。

        // Set<Integer> set = new HashSet<Integer>();//Set存储不重复无序元素
        // int repeat = -1;
        // for (int num : nums) {
        //     if (!set.add(num)) {
        //         repeat = num;
        //         break;
        //     }
        // }
        // return repeat;

        解法三:原地交换。题目说明尚未被充分使用,即 在一个长度为 n 的数组 nums 里的所有数字都在 0 ~ n-1 的范围内 。 此说明含义:数组元素的 索引 和 值 是 一对多 的关系
因此,可遍历数组并通过交换操作,使元素的 索引 与 值 一一对应(即 nums[i] = inums[i]=i )。因而,就能通过索引映射对应的值,起到与字典等价的作用。

        遍历中,第一次遇到数字 xx 时,将其交换至索引 xx 处;而当第二次遇到数字 xx 时,一定有 nums[x] = xnums[x]=x ,此时即可得到一组重复数字。  

算法流程:
遍历数组 numsnums ,设索引初始值为 i = 0 :

若 nums[i] = inums[i]=i : 说明此数字已在对应索引位置,无需交换,因此跳过;
若 nums[nums[i]] = nums[i]: 代表索引 nums[i]处和索引 i 处的元素值都为 nums[i] ,即找到一组重复值,返回此值 nums[i] ;
否则: 交换索引为 i 和 nums[i] 的元素值,将此数字交换至对应索引位置。
若遍历完毕尚未返回,则返回 -1−1 。

复杂度分析:
时间复杂度 O(N) : 遍历数组使用 O(N) ,每轮遍历的判断和交换操作使用 O(1) 。
空间复杂度 O(1) : 使用常数复杂度的额外空间。

        int i = 0;
        while(i < nums.length) {
            if(nums[i] == i) {
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i]) return nums[i];
            int tmp = nums[i];
            nums[i] = nums[tmp];
            nums[tmp] = tmp;
        }
        return -1;

3.二维数组的查找

        解法一:暴力求解,遍历数组。

        解法二:线性查找。暴力法未利用矩阵 “从上到下递增、从左到右递增” 的特点,显然不是最优解法。如下图所示,我们将矩阵逆时针旋转 45° ,并将其转化为图形式,发现其类似于 二叉搜索树 ,即对于每个元素,其左分支元素更小、右分支元素更大。因此,通过从 “根节点” 开始搜索,遇到比 target 大的元素就向左,反之向右,即可找到目标值 target 。

        int i = matrix.length - 1, j = 0;
        while(i >= 0 && j < matrix[0].length)
        {
            if(matrix[i][j] > target) i--;
            else if(matrix[i][j] < target) j++;
            else return true;
        }
        return false;

4.在排序数组中查找指定数字 

        排序数组中的搜索问题,首先想到 二分法 解决 

排序数组 nums中的所有数字 target形成一个窗口,记窗口的 左 / 右边界 索引分别为 left和 right ,分别对应窗口左边 / 右边的首个元素。

本题要求统计数字 target 的出现次数,可转化为:使用二分法分别找到 左边界 left和 右边界 right ,易得数字 target 的数量为 right - left - 1。

        // 搜索右边界 right
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= target) i = m + 1;
            else j = m - 1;
        }
        int right = i;
        // 若数组中无 target ,则提前返回
        if(j >= 0 && nums[j] != target) return 0;
        // 搜索左边界 right
        i = 0; j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] < target) i = m + 1;
            else j = m - 1;
        }
        int left = j;
        return right - left - 1;

        关于二分法的详细使用步骤,可以看这里:https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值