算法-(一维数组)

算法-(一维数组)

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

 

 

 

posted @ 2021-11-04 10:33  UpGx  阅读(132)  评论(0编辑  收藏  举报