算法与数据结构

算法

排序

插入排序

思想:通过构建有序数列,将新的元素,从右往左寻找,找到正确的位置进行插入。
步骤:1.从第二个元素开始,将新元素插入到前面已经排序好的子数组中;
2.新元素插入之后,新位置到原来位置之间的元素,全部向右平移一位;
3.重复前两个步骤,直至所有的元素排序完成。

public class InsertSort {
    /**
     * 思路:从左到右,每次把新元素正确插入到左边已经排序号的数组中
     */
    public void insert(int[] nums){
        int length = nums.length;
        for (int i=1;i<length;i++){
            int baseNum = nums[i];
            int j = i-1;
            while (j>=0 && nums[j]>baseNum){
                nums[j+1]=nums[j];
                j--;
            }
            nums[j+1]=baseNum;
        }
    }
}

复杂度:O(n^2)
优化思路:从右往左插入的时候,因为左边的数组已经排序好了,则可以利用二分查找法进行。

public void binaryInsert(int[] nums){
        int length = nums.length;
        for (int i=1;i<length;i++){
            int baseNum = nums[i];
            int left = 0;
            int right = i;
            while (left<right){
                int mid = (left+right)/2;
                if (nums[mid]<baseNum){
                    left=mid+1;
                }else {
                    right=mid;
                }
            }
            for (int j=i;j>left;j--){
                nums[j]=nums[j-1];
            }
            nums[left]=baseNum;
        }
    }

复杂度:O(nlogn)

快排

思路:分治算法
选择最左边的数字为基础数字,找到其在数组中的正确位置,然后将左边和右边的数组重复刚才的操作
1.根据基准数字找到其正确的位置:从右边开始循环,数字大于等于基准数字,则位置不变,右边索引-1继续找
当右边数字小于基准数字时,将右边索引的值,赋值给左索引的值,此时右边索引的值不一定是正确的
2.从左边开始循环,数字小于等于基准数字,则位置不变,左边索引+1继续找
当左边数字大于基准数字时,将左边索引的值,赋值给右索引的值,此时左边索引的值不一定是正确的
3. 1,2不断循环,直至左索引和右索引相等时停止,这时左索引的值不一定是正确的,需要将基准数字赋值给它
4.返回此时的左索引值,即为基准数字的正确索引位置

    public void quick(int[] num,int left,int right){
        if (left>=right){
            return;
        }
        Integer partition = partition(num, left, right);
        quick(num,left,partition-1);
        quick(num,partition+1,right);

    }

    public Integer partition(int[] num,int left,int right){
        int baseNum = num[left];
        while (left<right){
            while (left<right && baseNum<=num[right]){
                right--;
            }
            //此时right位置的数字不一定是正确的
            num[left]=num[right];
            while (left<right && baseNum>=num[left]){
                left++;
            }
            //此时left处的数字不一定是正确的
            num[right]=num[left];
        }
        //此时left处的数字不一定是正确的,要把基准数字赋值给它才是正确的
        num[left]=baseNum;
        return left;
    } 

复杂度:
平均复杂度:n logn
最坏复杂度:n^2

单调栈

下一个更大元素

题目:nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。

给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。

返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
    示例 2:

输入:nums1 = [2,4], nums2 = [1,2,3,4].
输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
  • 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。

提示:

1 <= nums1.length <= nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 104
nums1和nums2中所有整数 互不相同
nums1 中的所有整数同样出现在 nums2 中
方法一:暴力求解
时间复杂度:O(mn),其中 m 是 nums1的长度,n 是 nums2的长度。
方法二:单调递减栈+哈希表
时间复杂度:O(m+n),其中 m 是 nums1的长度,n 是 nums2的长度。我们需要遍历 nums2以计算 nums2中每个元素右边的第一个更大的值;需要遍历 nums1以生成查询结果。
思路:遍历num2中的元素,构建一个单调递减栈,遍历每个元素时,只要把当前元素和栈顶元素存到hashMap中,便利num1,将num1中的元素key获取value即可。

public int[] test(int[] arr,int[] part){
        Stack<Integer> stack = new Stack<>();
        HashMap<Integer,Integer> num2BigNum = new HashMap<>();
        int[] ans = new int[part.length];
        for (int i=arr.length-1;i>=0;i--){
            if (stack.size()==0 || stack.peek()>arr[i]){
            }else {
                while (stack.size()>0 && stack.peek()<=arr[i]){
                    stack.pop();
                }
            }
            if (stack.size()==0){
                num2BigNum.put(arr[i],-1);
            }else {
                num2BigNum.put(arr[i],stack.peek());
            }
            stack.push(arr[i]);
        }
        for (int i=0;i<part.length;i++){
            ans[i] = num2BigNum.get(part[i]);
        }
        return ans;
    }
  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值