算法记录|Day01 数组

数组

  • 理论基础
  • Leecode题目
    • 704 - 二分查找
    • 27 - 移除元素

理论基础

一维数组内的元素是连续存储的,所以数组中元素的地址,可以通过其索引计算出来。知道了数组的数据起始地址 B a s e A d d r e s s BaseAddress BaseAddress,就可以由公式 B a s e A d d r e s s + i ∗ s i z e BaseAddress + i * size BaseAddress+isize 计算出索引 i i i 元素的地址

Leecode题目

704 - 二分查找

1.解题思路

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。

(1)左闭右闭即[left, right]

  • 对应着搜索区间 [ 0 , a . l e n g t h − 1 ] [0,a.length-1] [0,a.length1],即 i = 0 , j = n − 1 i=0,j=n-1 i=0,j=n1
  • i < = j i<=j i<=j 意味着搜索区间内还有未比较的元素, i , j i,j i,j 指向的元素也可能是比较的目标
  • 若nums[middle]不是target,需更新 i , j i,j i,j ,搜索空间不能包含middle,所以 j = m − 1 j = m - 1 j=m1或者 i = m + 1 i = m + 1 i=m+1

(2)左闭右开即[left, right)

  • 对应着搜索区间 [ 0 , a . l e n g t h ) [0,a.length) [0,a.length),即 i = 0 , j = n i=0,j=n i=0,j=n
  • i < j ii<j 意味着搜索区间内还有未比较的元素, j j j 指向的一定不是查找目标
  • 若nums[middle]不是target,更新 i , j i,j i,j ,搜索空间不需要包含middle,所以 j = m j = m j=m或者 i = m + 1 i = m + 1 i=m+1

2.算法描述

算法描述 左闭右闭区间 [left, right]
前提 n n n 个元素的有序数组 A A A和一个待查找的 t a r g e t target target
S t e p 1 Step1 Step1 设置两个指针, i = 0 , j = n − 1 i=0,j=n-1 i=0,j=n1
S t e p 2 Step2 Step2 如果 i > j i \gt j i>j,结束查找,没找到
S t e p 3 Step3 Step3 设置 m = f l o o r ( i + j 2 ) m = floor(\frac {i+j}{2}) m=floor(2i+j) m m m 为中间索引, f l o o r floor floor 是向下取整( ≤ i + j 2 \leq \frac {i+j}{2} 2i+j 的最小整数)
S t e p 4 Step4 Step4 如果 t a r g e t < A m target < A_{m} target<Am 设置 j = m − 1 j = m - 1 j=m1,跳到第2步
S t e p 5 Step5 Step5 如果 A m < t a r g e t A_{m} < target Am<target 设置 i = m + 1 i = m + 1 i=m+1,跳到第2步
S t e p 6 Step6 Step6 如果 A m = t a r g e t A_{m} = target Am=target,结束查找,找到了

代码描述(左闭右闭即[left, right]):

class Solution {
    public int search(int[] nums, int target) {
       int i=0;
       int j = nums.length-1;
       while(i<=j){            
           int m = (i+j) >>> 1;
           if(nums[m]<target){
                i = m+1;
           }else if(nums[m]>target){
              j = m-1;
           }else{
              return m;
           }
       }
       return -1;
    }
}

代码描述(左闭右开即[left, right)):

class Solution {
    public int search(int[] a, int target) {
      int i = 0;
      int j = a.length;
      while(i<j){
          int m =(i+j)>>>1;
          if(a[m]<target){
              i = m+1;
          }else if(a[m]>target){
              j=m;
          }else{
              return m;
          }
      }
      return -1;
}
}

3. 总结

确定搜索空间
确定循环条件
搜索区间边界更新的条件
  • 补充:计算 m = (i + j) >>> 1 ,用的是无符号右移动运算符,因为i+j可能计算出一个负数。
  • int 占用 4 字节,32 比特,数据范围为:-2147483648 ~ 2147483647 [-2^31 ~ 2^31-1]。那么对于两个都接近 2147483647的数字而言,它们相加的结果将会溢出,变成负数。

27 - 移除元素

1. 题目分析

  • 前半段是有效部分,存储的是不等于 val 的元素。
  • 后半段是无效部分,存储的是等于 val 的元素。

输出有效部分元素的个数即可。

(1)暴力解法

算法描述 暴力解法
S t e p 1 Step1 Step1 建立for循环,遍历数组中每一个元素
S t e p 2 Step2 Step2 判断当前元素 n u m s [ i ] nums[i] nums[i]是否等于val
S t e p 3 Step3 Step3 如果不相等,跳转step1
S t e p 4 Step4 Step4 如果相等,将当前元素中后面的所有元素依次向前移动一位,更新 i 和 s i z e i和size isize
class Solution {
    public int removeElement(int[] a, int val) {
       int size = a.length;
       for(int i=0;i<size;i++){
           if(a[i] == val){
               for(int j =i+1;j<size;j++){
                   a[j-1] = a[j];
               }
               i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
           size--;//此时数组的大小-1
           }
           
       }
       return size;
    }
}

难点: s t e p 4 step4 step4:当前元素中后面的所有元素依次向前移动一位

  • 从第 i + 1 i+1 i+1个元素开始建立for循环
  • 循环完以后, i = i − 1 i =i-1 i=i1,因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
  • s i z e = s i z e − 1 size = size-1 size=size1此时数组的大小-1

(2) 双指针法

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

输出慢指针所在的位置即可。

算法描述 双指针法
S t e p 1 Step1 Step1 定义两个快慢指针 i , j i,j i,j
S t e p 2 Step2 Step2 用快指针 j j j循环遍历数组中的元素
S t e p 3 Step3 Step3 如果 n u m s [ j ] = = v a l nums[j]==val nums[j]==val,慢指针不移动
S t e p 4 Step4 Step4 如果 n u m s [ j ] 不等于 v a l nums[j]不等于val nums[j]不等于val,更新慢指针的元素,再向前移动 i = i + 1 i=i+1 i=i+1

算法记录|Day01 数组_第1张图片

图片描述(自用):阿珍和阿强一起穿过小森林,里面存在未知个数的恶魔。

  • 阿强发现当前不是恶魔,给阿珍看 a [ i ] = a [ j ] a[i] =a[j] a[i]=a[j],然后一起向前走一步, a [ i + + ] = a [ j ] , j + + a[i++] = a[j],j++ a[i++]=a[j],j++
  • 阿强发现了恶魔,阿珍被抓住,阿强往前走去找帮手
  • 阿强找到了不是恶魔的帮手,征服了恶魔,拯救了阿珍, a [ i ] = a [ j ] , i + + , j + + a[i] = a[j],i++,j++ a[i]=a[j],i++j++,各自向前走
  • 继续向前探路,直到走到尽头
    注意输出是移除目标元素的大小,大小刚好和阿珍(满指针)索引的大小相同

class Solution {
    public int removeElement(int[] a, int val) {
       int i =0;
       for(int j=0;j<a.length;j++ ){
           if(a[j]!=val){
               a[i++] =a[j];
           }
       }
   return i;    
}
}

总结:
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

你可能感兴趣的:(算法,leetcode,数据结构)