zoukankan      html  css  js  c++  java
  • 算法-(一维数组)

    算法-(一维数组)

    在我觉得算法是一种能够提升程序性能和面试必备的利器,尤其是去外企,或者一些好的企业。并且在写算法的同时,会锻炼到我们的逻辑思考能力和空间想象能力。所以接下来我想聊聊一些常用的算法,在之前的文章中聊到了一些零散的算法,比如翻转链表,以及深度拷贝链表。但是那些都不成体系。所以接下来的文章,我想聊聊把相同的算法知识点放在一起去聊聊。那本篇就从最基础的关于数组的算法开始聊起,并且我会提炼出一些解题方式,当然同时也有demo。

    合并数组

    1.合并两个数组

    • 前提 给两个递增的整数数组【nums1】和【nums】,和两个整数【m】和【n】分别表示两个数组的元素数量多少。
    • 要求】:合并两个数组,并且合并后的数组按照非递减的顺序进行排列。
    • 输入egnums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
    • 输出eg[1,2,2,3,5,6]
    • 【想法】:
      • 直接合并数组二到数组一,然后对数组一进行排序最简单,但是没有技术含量,并且时间复杂度是O(n)
        • View Code
      • 两个数组进行比较,因为数组不能直接替换,需要移动插入。已经知道两个数组都是依次递增,所以我们使用【从后向前】的插入方式是【最少移动数组元素】的最好选择。
        • 对数组一和数组二进行比较,从后向前比较
        • 第一轮:如果数组1的最后一个小于数组二的最后一个,则把数组二的最后一个元素放在数组一的最后元素中 那就变成了 【123006】。然后第二个数组前移,第一个数组下标不变。同时赋值的下标增加一。
        • 以此类推,如果数组1中的一个元素小于数组二中的某个元素,那就把数组一中的这个元素放在上次赋值位的下一位。
        • View Code 

    2.合并n个数组

    • 【想法】:可以采用归并的思想,把数组进行两两合并。比如说现在要合并4个数组,那我就写一个方法,这个方法的返回值是一个数组,传递的参数是两个数组。在方法内,把这两个数组放在一个新建的数组中,并返回新建的数组。这个就好办了,循环对比两个数组,数组一的元素大就把数组二的元素放在新数组中,最后把剩余的元素直接放在数组中。
    •     private static int[] mergeTwoArray(int[] arr1, int[] arr2) {
              int length1 = arr1.length;
              int length2 = arr2.length;
              int[] newArr = new int[length1 + length2];
              int i=0;
              // 数组一的指针
              int j=0;
              // 数组二的指针
              int k=0;
              while (j< length1 && k<length2){
                  if (arr1[j] <= arr2[k]){
                      newArr[i++]=arr1[j++];
                  }else {
                      newArr[i++]=arr2[k++];
                  }
              }
              //如果那个数组没有循环完成,就直接拼接到后面。
              while (j<length1){
                  newArr[i++]=arr1[j++];
              }
              while (k<length2){
                  newArr[i++]=arr2[k++];
              }
              return newArr;
          }
      View Code

    删除数组元素

    1. 删除数组中和所给数字一样的元素。

    • 前提】: 给一个数组nums和一个值val
    • 【要求】:移除数组中所有数值是val的,并且返回移除后的数组长度,不能使用额外的数组,必须使用o(1)额外空间,并且原地修改输入的数组。元素的顺序可以改变。
    • 【输入】:nums=【3,2,2,3】 val =【3】
    • 输出】:2 ,nums【2,2】
    • 【想法】:
      • 【双指针交换移除】左右两个指针向中间走,实际上就是和原来数字不同的都放在左边,相同的都放在右边。
        •  左边的指针如果和所给的数字一样,则把右侧的指针所指的地方的数据放在左侧,并且左侧不动,右侧继续前进。
        •  如果不一样,左侧的指针则向前继续走。
      •     // 从两端开始,向中间遍历。
            private static int removeElement2(int[] nums, int val) {
                int ans = nums.length;
                // 当两个指针相遇,则循环结束
                for (int i = 0; i < ans; ) {
                    //一个指针从左边开始如果和给定的数字相同,则把右边的数据给最左边,同时右边的指针减一
                    if (nums[i]==val){
                        nums[i]=nums[ans-1];
                        ans--;
                    }else {
                        i++;
                    }
                }
                return ans;
            }
        View Code
      • 【双指针移动】循环每个元素,当前循环元素如果和所给元素不一样,则把当前元素复制给前一个元素,并且变量增加一,这样的话,前面的元素都不是所给的元素,一直到循环结束,返回变量。
      •     private static int removeElement(int[] nums, int val) {
                int ans = 0;
                for (int num : nums) {
                    if (num != val) {
                        nums[ans] = num;
                        ans++;
                    }
                }
                return ans;
            }
        View Code

    2. 删除有序数组的重复项

    • 前提】: 给一个有序数组nums
    • 【要求】删除数组中相同的数字,让每个元素只能出现一次
    • 【输入】nums =[1,1,2]
    • 输出2 ,nums【1,2】
    • 【想法】快慢指针,快指针先走,慢指针在后,当快指针发现和和慢指针一样的时候,慢指针停止移动,快指针继续向前走,当快指针发现和慢指针不一样的时候,快指针把他当前的位置放在慢指针的下一个位置,然后慢指针向前移动到新元素的位置上。
      • 比如: 1,1 ,2 快指针的下标在1,慢指针的下标在0
      • 这个时候快指针的位置是1,慢指针也是1,那慢指针就不动了,
      • 快指针移动到2【下标是2的位置上的数字也是2】
      • 这个时候快指针发现2 和 慢指针位置上你的一不一样,那么就把这个2移动到慢指针的下一位,就变成了1,2,1.
      • 当然我们维护了一个变量去记录变化的次数,所以只用打印变量的次数的内容就行,那就是1 ,2
      •     // 这里其实就是快慢指针,都是从头开始遍历,当慢指针等于快指针的位置的时候,
            // 慢指针不变,快指针继续向前,当他们不相同的时候,把快指针的内容赋值给慢指针的后一位数据,慢指针的指针数也随着增加一
            private static int removeElement(int[] nums) {
                int length = nums.length;
                // slow 初始为1的原因是,题目要求每个元素只能出现一次
                int slow = 1;
                for (int fast = 0; fast < length; fast++) {
                    if (nums[slow - 1] != nums[fast]) {
                        nums[slow] = nums[fast];
                        slow++;
                    }
                }
                return slow;
            }
        View Code

    元素奇偶移动

    1.奇偶数分离

    • 前提 给一个整数数组
    • 【要求】让数组中偶数位于数组前面,奇数位于数组后面
    • 【输入】【3,1,2,4】
    • 输出【2,4,3,1】or 【4,2,3,1】 or 【2,4,1,3】 or 【4,2,1,3】 只要满足奇数在前都可,不论任何顺序
    • 【想法】
      • 【新数组赋值】:循环把奇数放在数组的前面,再循环放偶数。
        •     private static int[] sortArrayByParityLevel1(int[] A) {
                  int[] ans = new int[A.length];
                  int t = 0;
                  for (int i = 0; i < ans.length; i++) {
                      // 是偶数就放在数组前面
                      if (A[i] % 2 == 0) {
                          ans[t++] = A[i];
                      }
                  }
                  for (int i = 0; i < ans.length; i++) {
                      if (A[i] % 2 != 0) {
                          ans[t++] = A[i];
                      }
                  }
                  return ans;
              }
          View Code
      • 【双指针交换寻找】:
        • 还是和上面数组删除元素的方法一样。一个指针从前面走,一个指针从后面走。
        • 然后两个指针进行对比,如果前面的是偶数,后面的是奇数,则把位置进行交换
        • 接着两个指针继续向前,直到交汇为止。
      •     private static int[] sortArrayByParityd(int[] A) {
                int left = 0;
                int right = A.length - 1;
                for (int i = 0; i < A.length; i++) {
                    // 左边大于右边,证明左边是奇数 那就把右边和的左边的进行颠倒
                    if (A[left] % 2 > A[right] % 2) {
                        int temp = A[left];
                        A[left] = A[right];
                        A[right] = temp;
                    }
                    // 左边是偶数 左边向前推进
                    if (A[left] % 2 == 0) {
                        left++;
                    }
                    // 左边不是偶数 右边边向前推进
                    if (A[left] % 2 != 0) {
                        right--;
                    }
                }
                return A;
            }
        View Code

    2.调整后的顺序和原始数组顺序一致(和第一题的要求不同的是,在对他的奇偶换位置的同时,他们的顺序是不能变的

    • 【想法】:循环遍历,如果某个数的右边是偶数,左边是奇数,则把他们交换位置
      • 例【2,4,3,1】 第一轮 【2,3,1,4】第二轮 【3,1,2,4】
      •   
            //左边是偶数 右边是奇数 则进行交换 否则继续扫描
            private static int[] reOrderArray(int[] array) {
                int n = array.length;
                for (int i = 0; i < n; i++) {
                    for (int j = 0; j < n - 1 - i; j++) {
                        // 左边是偶数,并且右边是奇数,则交换他们的位置
                        if ((array[j] & 1) == 0 && (array[j + 1] & 1) == 1) {
                            int tmp = array[j];
                            array[j] = array[j + 1];
                            array[j + 1] = tmp;
                        }
                    }
                }
                return array;
            }
        View Code

     

  • 相关阅读:
    Python requests 获取网页一般的方法
    python 开发环境安装及配置
    python os模块常用方法及属性小结
    python sys 模块常用方法小结
    python datetime 模块常用方法小结
    python 异常继承关系及自定义异常的实现
    python 第三方模块的安装及模块导入说明
    python 中 if __name__ == '__main__' 的解释
    Bootstrap 标签页(Tab)插件
    Bootstrap 滚动监听(Scrollspy)插件
  • 原文地址:https://www.cnblogs.com/UpGx/p/15507062.html
Copyright © 2011-2022 走看看