[代码随想录笔记]第三章 数组

第三章 数组

数组的理论基础
  • 数组下标都是从0开始
  • 数组在内存空间的地址是连续的
    • 数组的元素不能删除,只能被覆盖。如果是C++编程,要注意vector和array的区别
二分查找

在一个有序无重复的数组nums中,寻找一个目标元素target,如果找到了就返回对应的下标,如果没找到就返回-1。

  • 写法一

    • 区间为左闭右闭
    int search(int* nums, int numsSize, int target){
        int left,right,middle;
        left = 0;
        right = numsSize - 1;
        while(left <= right){
            middle = (left + right) / 2;
            if (nums[middle] > target){
                right = middle - 1;
            }
            else if (nums[middle] < target){
                left = middle + 1;
            }
            else if (nums[middle] == target){
                return middle;
            }
            }
        return -1;
        }
    
  • 写法二

    • 区间为左闭右开
    int search(int* nums, int numsSize, int target){
        int left,right,middle;
        left = 0;
        right = numsSize;
        while(left < right){
            middle = (left + right) / 2;
            if (nums[middle] > target){
                right = middle;
            }
            else if (nums[middle] < target){
                left = middle + 1;
            }
            else if (nums[middle] == target){
                return middle;
            }
            }
        return -1;
        }
    
移除元素

为什么题目中没有要求返回移除元素后的数组?因为数组中的元素无法真正移除,只能靠后一个元素覆盖前一个元素,返回移除后的数组没有意义

  • C++中的函数传递

    • 值传递:有一个形参向函数所属的栈拷贝数据的过程,如果值传递的对象是类对象或是大的结构体对象,将耗费一定的时间和空间。

      void fun(int x){
       
      x += 5; //修改的只是y在栈中copy x,x只是y的一个副本,在内存中重新开辟的一块临时空间把y的值 送给了x;这样也增加了程序运行的时间,降低了程序的效率。
       
      }
       
      void main(void){
       
      int y = 0;
       
      fun(y);
       
      cout<<\"y = \"<<y<<endl; //y = 0;
      }
      
    • 指针传递:同样有一个形参向函数所属的栈拷贝数据的过程,但拷贝的数据是一个固定为4字节的地址。

      void fun(int *x){
       
      *x += 5; //修改的是指针x指向的内存单元值
       
      }
       
      void main(void){
       
      int y = 0;
       
      fun(&y);
       
      cout<<<<\"y = \"<<y<<endl; //y = 5;
      }
      
    • 引用传递:同样有上述的数据拷贝过程,但其是针对地址的,相当于为该数据所在的地址起了一个别名。

      void fun(int &x){
       
      x += 5; //修改的是x引用的对象值 &x = y;
       
      }
       
      void main(void){
       
      int y = 0;
       
      fun(y);
       
      cout<<<<\"y = \"<<y<<endl; //y = 5;
      }
      
  • 暴力解法

    int removeElement(int* nums, int numsSize, int val){
        int i,j;
        int temp=0;
        for(i=0;i<numsSize;i++){
            if (nums[i] == val){
                for(j=i;j<numsSize-1;j++){
                    nums[j] = nums[j+1];
                }
            i--;
            numsSize--;
            }
        }
        return numsSize;
    }
    
  • 双指针法

​ 注意nums[slowIndex++]的含义

int removeElement(int* nums, int numsSize, int val){
    int slow = 0;
    int fast;
    for (fast = 0;fast < numsSize;fast++){
        if (nums[fast] != val){
            nums[slow++] = nums[fast];#等价于nums[slow] = nums[fast];slow++;
        }
    }
    return slow;
}
补充

i++与++i的区别:

(简单记忆):

  • i++ 是先赋值在再自加,如:i = 1;k = i++;此时k的值为1,i的值为2;即i先把自身的值赋给了k之后才进行的自加。

  • ++i是先自加在赋值,如:i = 1;k = ++i;此时k的值为2,i的值也为2;即i先进行自加,再将自加后的值赋给k。

  • 当i++或者++i单独使用,没有其他表达式参与运算时,它们两个所实现的效果是一样的,都是实现自加1的效果。

写了几段代码并进行反汇编,结果如下:

在这里插入图片描述

可以清楚看到,a=i++是把i原来的值赋给eax,最后直接赋给a(-0x8(%rbp));而b=++j则是先加1再赋值。

长度最小的子数组
  • 暴力解法

    int minSubArrayLen(int target, int* nums, int numsSize){
        int i,j;
        int sum = 0;
        int length,final_length;
        length = 0;
        final_length = INT_MAX;
        for (i = 0;i < numsSize;i++){
            sum = 0;
            for (j = i;j < numsSize;j++){
                sum += nums[j];
                if (sum >= target) {
                    length = j - i + 1;
                    final_length = final_length < length ? final_length : length;
                    break;
                }
            }
        }
        return final_length == INT_MAX ? 0 : final_length;
    }
    
  • 滑动窗口(双指针法)

    关键:

    • 窗口内的元素是什么
    • 如何移动窗口的起始位置
    • 如何移动窗口的终止位置
int minSubArrayLen(int target, int* nums, int numsSize){
    int final_length = INT_MAX;
    int i,j;
    int sum = 0;
    i = 0;
    int length = 0;
    for (j = 0;j < numsSize;j++) {
        sum += nums[j];
        while (sum >= target) {
            length = j - i + 1;
            final_length = final_length < length ? final_length : length;
            sum -= nums[i++];
        }
    }
    return final_length == INT_MAX ? 0 : final_length;
}
螺旋矩阵Ⅱ
  • 补充

    在c语言中,使用变量前,需要先对变量的值进行初始化。数组在内存中占用一片连续的存储块。而c语言提供了memset函数(头文件string.h)对数组进行组团赋值。

​ **函数原型:**void memset ( void *s , char ch, unsigned n )

​ memset函数是对n个字节进行赋值;而char类型占1个字节,但是int类型占4个字节,所以对int、 short等类型赋值时,需要乘上字节数。并且memset赋值试会直接将数组拆分成总字节数个字节赋 值,并不会将四个字节看成一个整体,也就是说对整数类型数组赋值为非0的数并不能得到预期的结 果。

  • 错误代码

    /**
     * Return an array of arrays of size *returnSize.
     * The sizes of the arrays are returned as *returnColumnSizes array.
     * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
     */
    int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
        int** matrix = malloc(sizeof(int*) * n);
        *returnSize = n;
        *returnColumnSizes = malloc(sizeof(int) * n);
        int k;
        for (k = 0; k < n; k++) {
            matrix[k] = malloc(sizeof(int) * n);
            memset(matrix[k], 0, sizeof(int) * n);
            (*returnColumnSizes)[k] = n;
        }
        
        int temp = n * n;
        int highboard,lowboard,leftboard,rightboard;
        highboard = 0;
        lowboard = n-1;
        leftboard = 0;
        rightboard = n-1;
        int i = 0;
        int j = 0,flag = 1;
        while (flag <= temp){        
            matrix[i][j] = flag;
            if (i == highboard && j < rightboard) {
                if (j == leftboard && highboard != 0) {
                    leftboard += 1;
                }
                j += 1;
            }
            else if (j == rightboard && i < lowboard) {
                if (i == highboard) {
                    highboard += 1;
                }
                i +=1;
            }
            else if (i == lowboard && j > leftboard) {
                if (j == rightboard) {
                    rightboard -= 1;
                }
                j -= 1;
            }
            else if (j == leftboard && i > highboard) {
                if (i == lowboard) {
                    lowboard -= 1;
                }
                i -= 1;
            }
            flag += 1;
        }
        return matrix;
    }
    

    边界值变了后,数组下标也变了,导致其永远能满足判断条件。最好是以“圈”为循环单位而非已遍历的元素个数

  • 模拟

    处理原则需要统一,否则容易欠考虑

    /**
     * Return an array of arrays of size *returnSize.
     * The sizes of the arrays are returned as *returnColumnSizes array.
     * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
     */
    int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
        int** matrix = malloc(sizeof(int*) * n);
        *returnSize = n;
        *returnColumnSizes = malloc(sizeof(int) * n);
        int k;
        for (k = 0; k < n; k++) {
            matrix[k] = malloc(sizeof(int) * n);
            memset(matrix[k], 0, sizeof(int) * n);
            (*returnColumnSizes)[k] = n;
        }
        
        int i;
        int j;
        int loop = n / 2;//循环圈数 可以这么理解:画个对角线,看其一半有几格(奇数向下取整,忽略的那格另外考虑)
        int startx = 0;
        int starty = 0;
        int offset = 1;//每次循环通过偏移量来控制圈的边长
        int flag = 1;
    
        while (loop--){
            i = startx;
            j = starty;
            for (j = starty;j < starty + n - offset;j++) {
                matrix[i][j] = flag++;//注意flag++是先赋值再自加
            }
            for (i = startx;i < startx + n - offset;i++) {
                matrix[i][j] = flag++;
            }
            for (;j > starty;j--) {
                matrix[i][j] = flag++;
            }
            for (;i > startx;i--) {
                matrix[i][j] = flag++;
            }
    
            startx++;
            starty++;
            offset += 2;//第一圈边长被占了两格,第二圈边长须要再减二
        }
        i = n / 2;
        if (n % 2) {
            matrix[i][i] = flag;
        }
        return matrix;
    }
    

github链接:https://github.com/Chigland/Code-learing-note

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值