首页 > 编程语言 >代码随想录算法训练营第一天 | 数组part01:数组理论基础,704. 二分查找,27. 移除元素 977.有序数组的平方

代码随想录算法训练营第一天 | 数组part01:数组理论基础,704. 二分查找,27. 移除元素 977.有序数组的平方

时间:2024-08-28 15:27:53浏览次数:15  
标签:val nums int 随想录 数组 移除 left size

数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合

数组徐璈注意的是:

  • 数组的下标都是从0开始的
  • 数组内存空间是的地址是连续的
    正因为舒适的内存空间是连续的,所以在删除和增添元素的时候,需要移动其他元素的地址。

在c++中,vector的底层实现是array,严格来说,vector是容器,不是数组。

数组的元素不能删除,只能被覆盖。

704 二分查找
题目链接:https://leetcode.cn/problems/binary-search/

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

之前做过,但是现在一看还是很懵,没有一个清晰的解题思路。先看以便随想录上的解题思路,自己实现,总结收获。

解题思路:
首先需要看题的条件:有序数组,数组中无重复元素。如果是包含重复元素的数组,使用二分法查找返回元素下标可能不是唯一的。

区间的定义两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
第一种解法 左闭右闭:
[left, right]区间注意:

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
  • if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

自己按照思路写出的代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = **nums.size()**-1;
        while(left <= right){
            //int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2 这里不是很懂。
            **int mid = (right + left)/2;**
            if(nums[mid] > target) {
                **right = mid;** //这里应该是right=mid-1,因为如果当前mid对应的值大于目标值,应该在[left,mid-1]区间继续找,因为是双闭的区间。
            }else if(nums[mid] < target){
                **left = mid;** //所以这里也就是left = mid+1
            }else return mid;                    
        }
        return -1;
    }
};

总结:
vector的size .size()
为什么要用left + ((right - left) / 2):
在计算中间值时,常见的表达式是 int middle = (left + right) / 2;。然而,当 left 和 right 是非常大的整数时,它们的和 left + right 可能会超过整数的最大值,从而导致溢出错误。此时,结果将是不正确的,可能会引发程序错误或崩溃。

第二种解法:左闭右开[left, right)
左闭右开时,仅需注意while(left < right) 两个不能相等
if(nums[mid] > target) right = mid; 即可

27.移除元素
题目链接:https://leetcode.cn/problems/remove-element/description/

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
返回 k。

题目分析:
原地:不使用额外的数组空间,在原地修改输入数组并在O(1)额外空间的条件下完成。
元素顺序可以改变,不需要考虑数组中超出新长度后面的元素。

暴力解法
思路:依次遍历数组中的所有元素,若等于val,size--,否则继续遍历。这时如何改变nums数组的值?即遇到值=val如何让数组后边的值覆盖前边的值。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for(int i = 0;i < size;i++){
            if(nums[i] == val){
                **for(int j = i+1; j < size; j++){ //遇到数组中值=val,让后一个数组值覆盖当前值**
**                    nums[j-1] = nums[j]; **
                }
            **i--;// i--是当前值被后值覆盖,所以是新值,在下一轮循环还需要针对当前的i值做判断**
            size--;
            }
        }
        return size;
    }
};

重点 双指针法:
我的印象是设置一个fast一个slow指针。一个用于遍历数组,一个用于指示删除元素后数组的下标。
看完代码随想录后:
遇到数组值=val,fast继续向后遍历,slow不变,之后依次覆盖前面数组数值。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        int slow = 0;
        for(int fast = 0; fast < size; fast++){
            //错误写法 这里我想错了,总想等于val的时候应该做什么操作。
            // if(nums[fast] == val){
            //     fast++;
            //     nums[fast-1] = nums[fast];
            // }
            // else slow++;
            //只需要nums[fast] != val,才去给nums[slow]赋值就可以了。
            if(nums[fast] != val)
                nums[slow++] = nums[fast];
        }
        return slow;
    }
};

总结:
暴力解法注意双层遍历让nums数组后值覆盖前值。
双指针法注意只有nums[fast] != val,再去给nums[slow]赋值。

977.有序数组的平方
题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

题目分析
数组是非递减,输出的新数组要求也按照非递减排序。
我的思路
这里给每一个数组元素平方在返回比较简单,但是如何返回的数组元素也按照非递减的顺序排列,没有太好的思路。依旧是双指针法,双指针怎么用?
看完随想录后
其实挺简单,让两个指针分别指向头和尾,定义一个新数组,两指针依次向中间遍历,看平方值的大小来判断哪个先放入新数组。

我的错误解法

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> result;
        int i = 0, j = nums.size()-1;
        while(i <= j){
            //应该预先分配好result的值,再向数组加元素,这样减少频繁push_back
            //这个问题很大,我想的是如果i的nums值<j的nums值,就先向数组加入i的值,再加入j的值,这样是不对的。
            if(nums[i] * nums[i] < nums[j] * nums[j]){
                result.push_back(nums[i] * nums[i]);
                result.push_back(nums[j] * nums[j]);
            }
            if(nums[i] * nums[i] == nums[j] * nums[j]){
                result.push_back(nums[i] * nums[i]);
                result.push_back(nums[i] * nums[i]);
            }
            i++;
            j--;
        }
        return result;
    }
};

正确解法:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> result(nums.size(),0);
        int i = 0, j = nums.size()-1;
        //定义一个新的全局k值,用于新数组的下标值
        int k = j;
        while(i <= j){
            // j--和i++只需要在其中nums[i]和nums[j]加入了新数组才用
            if(nums[i] * nums[i] < nums[j] * nums[j]){
                result[k--] = nums[j] * nums[j];
                j--;
            }else{
                result[k--] = nums[i] * nums[i];
                i++;
            }
        }
        return result;
    }
};

总结
我觉得最大的问题就是我总想着双指针i和j一起+或者-,这样是不对的,当满足条件仅改变其中一个就可以。

标签:val,nums,int,随想录,数组,移除,left,size
From: https://www.cnblogs.com/zhslog/p/18384162

相关文章

  • 2024-08-28:用go语言,给定一个从1开始、长度为n的整数数组nums,定义一个函数greaterCount
    2024-08-28:用go语言,给定一个从1开始、长度为n的整数数组nums,定义一个函数greaterCount(arr,val)可以返回数组arr中大于val的元素数量。按照以下规则进行n次操作,将nums中的元素分配到两个数组arr1和arr2中:1.第一次操作将nums[1]加入arr1。2.第二次操作将nums[2]加入arr2。3.对......
  • 【力扣】3145.大数组元素的乘积
    题目描述一个非负整数 x 的 强数组 指的是满足元素为2的幂且元素总和为 x 的最短有序数组。下表说明了如何确定 强数组 的示例。可以证明,x 对应的强数组是独一无二的。数字二进制表示强数组100001[1]801000[8]1001010[2,8]1301101[1,4,8]2310111[1,2,4,16]......
  • 给自己复盘的随想录笔记-链表练习题(在整理ing)
    删除链表的倒数第N个节点双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。思路是这样的,但要注意一些细节。分为如下几步:推荐大家使用虚拟头结点,这样方便处理删除实际头结点的逻辑,定......
  • 代码随想录day43 || 300 最长递增子序列,674 最长连续递增子序列,718 最长重复子数组
    300最长递增子序列varpath[]intvarresintfunclengthOfLIS(nums[]int)int{ //尝试回溯思路 iflen(nums)==1{ return1 } path=[]int{} res=0 backtracking(nums) returnres}funcbacktracking(nums[]int){ iflen(nums)==0{ iflen(pat......
  • 在浏览器上使用transformers.js运行(WebGPU)RMBG-1.4进行抠图(背景移除)
    在浏览器上使用transformers.js运行(WebGPU)RMBG-1.4进行抠图(背景移除)说明:首次发表日期:2024-08-28官方Github仓库地址:https://github.com/xenova/transformers.js/tree/main/examples/remove-background-client准备下载onnx模型文件:https://huggingface.co/briaai/RMBG-1.......
  • Day09_0.1基础学习MATLAB学习小技巧总结(9)——数组运算
    利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。素材来源“数学建模清风”特此说明:本博客的内容只在于总结在使用matlab中的一些小技巧,并非教程,若想系统的学习MATLAB,也可以移步......
  • 代码随想录算法day24 | 贪心算法part02 | 122.买卖股票的最佳时机II,55. 跳跃游戏,45.跳
    122.买卖股票的最佳时机II本题解法很巧妙,本题大家可以先自己思考一下然后再看题解,会有惊喜!力扣题目链接(opensnewwindow)给定一个数组,它的第 i个元素是一支给定股票第i天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次......
  • 指针(二):数组指针
    目录数组名的理解数组整个地址与数组首元素地址区别指针的形式访问数组冒泡排序二级指针指针数组指针数组模拟二维数组数组名的理解在介绍数组指针之前先通过一段代码了解一下数组名的本质是什么。#include<stdio.h>intmain(){ intarr[]={1,2,3,4,5};......
  • 代码随想录训练营 Day42打卡 动态规划 part09 188.买卖股票的最佳时机IV 309. 最佳买
    代码随想录训练营Day42打卡动态规划part09一、力扣188.买卖股票的最佳时机IV给你一个整数数组prices和一个整数k,其中prices[i]是某支给定的股票在第i天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成k笔交易。也就是说,你最多可以买k次......
  • 【Leetcode_Hot100】普通数组
    普通数组53.最大子数组和56.合并区间189.轮转数组238.除自身以外数组的乘积41.缺失的第一个正数53.最大子数组和方法一:暴力解依次遍历数组中的每个子数组,进而判断res的最大值超时classSolution{publicintmaxSubArray(int[]nums){intres=0;......