代码随想录第一天||二分法||移除元素

704.二分查找

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

首先,假设数组元素大从大到小是升序的。

一开始,我拿到题目,觉得这个题目很简单,但是,编写代码过程中,遇到两个问题

(1)如何求解数组的长度?

(2)“nums[middle]<target”还是“nums[middle]<=target”,它们之间存在什么区别?

以下是我的代码。我采用闭区间的方案。

#include<iostream>
#include<string>
#include<cmath>
#include<vector>

using namespace std;
//template<typename T, size_t N>
//size_t getArrayLength(T(&)[N])
//{
//	return N;
//}
//
//int Get_length_array(int array[]) {
//
//}

class arraysolution {
public:
	//闭区间方案
	int half_find(vector<int> &sum, int target) {  //在函数参数中,数组类型应该包含数组元素的类型和数组的维度。例如,int array[] 或 int* array 表示传递一个整数类型的一维数组作为函数参数。

	//int half_find(int sum[], int target,int len) {  //在函数参数中,数组类型应该包含数组元素的类型和数组的维度。例如,int array[] 或 int* array 表示传递一个整数类型的一维数组作为函数参数。
		//int arr[] = { 1, 2, 3, 4, 5 };
		//int len = sizeof(sum) / sizeof(sum[0]);//在 32 位架构下,int 类型的大小通常为 4 字节。因此,一个 int 类型的数组 arr[N] 在内存中占用的字节数为 N * sizeof(int),即数组长度乘以元素类型的大小。对于 int arr[10],它占用的空间大小为 40 字节。
		//int len =  getArrayLength(sum);
		//当将数组作为参数传递给函数时,由于数组名被转换为指向第一个元素的指针,因此实际上传递给函数的是一个指向 int 类型的指针。在函数内部接收数组参数的形参也需要声明为指针类型,例如 int* arr。因此,在函数内部使用 sizeof(arr) 得到的结果是指针变量的大小(通常为 4 字节),而不是整个数组所占用的空间大小。如果需要在函数内部获取数组长度,可以采用先将数组长度作为另一个参数进行传递的方式,或者使用模板函数和指针等技术。
		//

		//typedef std::array<int,4> Myarray; 
	//	Myarray c0 = { 0,1,2,3 };
	//
	 display contents " 0 1 2 3"
	//	for (const auto& it : c0) {
	//		std::cout << " u << it;
	//	}
	//	std::cout << std::endl!
	//	// display size " 4"std::cout <<  u << c0.size();std::cout << std::endl;
	//	return (0);


		int left = 0;
		int right = sum.size()-1;//size不能用于返回数组长度;size可用于字符串等
		//int right = len - 1;
		while (sum[left] <= sum[right]) {
			int middle = int((left + right) / 2);
			if (sum[middle] < target) {//为啥这里<=呢?
				left = middle + 1;
			}
			else if (sum[middle] > target) {
				right = middle - 1;
			}
			else {
				return middle;
			}
			//cout << middle;
		}
		return -1;
	}
};

int main() {
	/*int i = 0
		cin >> array[i] >> " ";
	i++;*/
	arraysolution s1;
	//int array[9] = { 0,2,3,4,5,6,7,8,9 };
	vector<int> sums= { 0,2,3,4,5,6,7,8,9 };
	int target = 9;
	int result = s1.half_find(sums, target);
	cout << result;
	return 0;
}

运行结果如下: 

 

其实,数组操作没有.size()求长度;而且,数组做函数参数时,仅仅是以指针的方式传递第一个节点,当将数组作为参数传递给函数时,由于数组名被转换为指向第一个元素的指针,因此实际上传递给函数的是一个指向 int 类型的指针。在函数内部接收数组参数的形参也需要声明为指针类型,例如 int* arr。因此,在函数内部使用 sizeof(arr) (sizeof函数是获得)得到的结果是指针变量的大小(通常为 4 字节),而不是整个数组所占用的空间大小。如果需要在函数内部获取数组长度,可以采用先将数组长度作为另一个参数进行传递的方式,或者使用模板函数和指针等技术。如果采用下面的sizeof()函数;

int arr[] = { 1, 2, 3, 4, 5 };
int len = sizeof(sum) / sizeof(sum[0]);

无论输入什么测试数组,都会输出第二个元素数值,这是因为,int len始终等于2(在 64 位架构下,int 类型的大小通常为 4 字节,而指针的大小通常为 8 字节。)如下:

#include<iostream>
#include<string>
#include<cmath>
#include<vector>

using namespace std;
//template<typename T, size_t N>
//size_t getArrayLength(T(&)[N])
//{
//	return N;
//}
//
//int Get_length_array(int array[]) {
//
//}

class arraysolution {
public:
	//闭区间方案
	int half_find(vector<int> &sum, int target) {  //在函数参数中,数组类型应该包含数组元素的类型和数组的维度。例如,int array[] 或 int* array 表示传递一个整数类型的一维数组作为函数参数。

	//int half_find(int sum[], int target,int len) {  //在函数参数中,数组类型应该包含数组元素的类型和数组的维度。例如,int array[] 或 int* array 表示传递一个整数类型的一维数组作为函数参数。
		//int arr[] = { 1, 2, 3, 4, 5 };
		int len = sizeof(sum) / sizeof(sum[0]);//在 32 位架构下,int 类型的大小通常为 4 字节。因此,一个 int 类型的数组 arr[N] 在内存中占用的字节数为 N * sizeof(int),即数组长度乘以元素类型的大小。对于 int arr[10],它占用的空间大小为 40 字节。
		//int len =  getArrayLength(sum);
		//当将数组作为参数传递给函数时,由于数组名被转换为指向第一个元素的指针,因此实际上传递给函数的是一个指向 int 类型的指针。在函数内部接收数组参数的形参也需要声明为指针类型,例如 int* arr。因此,在函数内部使用 sizeof(arr) 得到的结果是指针变量的大小(通常为 4 字节),而不是整个数组所占用的空间大小。如果需要在函数内部获取数组长度,可以采用先将数组长度作为另一个参数进行传递的方式,或者使用模板函数和指针等技术。
		//

		//typedef std::array<int,4> Myarray; 
	//	Myarray c0 = { 0,1,2,3 };
	//
	 display contents " 0 1 2 3"
	//	for (const auto& it : c0) {
	//		std::cout << " u << it;
	//	}
	//	std::cout << std::endl!
	//	// display size " 4"std::cout <<  u << c0.size();std::cout << std::endl;
	//	return (0);


		int left = 0;
		//int right = sum.size()-1;//size不能用于返回数组长度;size可用于字符串等
		int right = len - 1;
		while (sum[left] <= sum[right]) {
			int middle = int((left + right) / 2);
			if (sum[middle] < target) {//为啥这里<=呢?
				left = middle + 1;
			}
			else if (sum[middle] > target) {
				right = middle - 1;
			}
			else {
				return middle;
			}
			//cout << middle;
		}
		return -1;
	}
};

int main() {
	/*int i = 0
		cin >> array[i] >> " ";
	i++;*/
	arraysolution s1;
	//int array[9] = { 0,2,3,4,5,6,7,8,9 };
	vector<int> sums= { 0,2,3,4,5,6,7,8,9 };
	int target = 9;
	int result = s1.half_find(sums, target);
	cout << result;
	return 0;
}

 同时,也有朋友建议,可以使用数据结构里的顺序表。

第二个问题,我的理解如下:

如图所示,使用左闭右闭的方案:

假设target=2,第一次迭代,middle对应的值小于target,如果我们取“>”,这就代表在【middle,right】中不存在target,则right=middle-1;相应的,如果middle对应的元素值大于target,则【left,middle】中都不包含target,则left=middle+1.

注意:在左闭右闭区间内,left=right是有意义的,所以要写“left<=right”

下面看一下,左闭右开的情况

在左闭右开区间内,left=right是无意义的,所以要写“left<right”,另外,right代表的左边界是虚的,没有元素,所以在缩进边界时,牵扯到right,就不用middle-1了,左边界不用动。

下面是左闭右开的代码:

while (left < right) {
			int middle = int((left + right) / 2);
			if (sum[middle] < target) {//为啥这里<=呢?
				left = middle + 1;
			}
			else if (sum[middle] > target) {
				right = middle;
			}
			else {
				return middle;
			}
			//cout << middle;
		}

运行结果:

27.移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。

示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

暴力解法的时间复杂度为O(n^{2})

// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
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++) {
                    nums[j - 1] = nums[j];
                }
                i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;

    }
};

所以,使用双指针(快慢指针)来解决这个问题,可以降低时间复杂度。

定义一个快指针和一个慢指针,快指针向前寻找元素值,慢指针紧跟其后储存新的数组元素值,当快指针寻找到目标元素时,慢指针暂停,快指针将下一个元素赋给慢指针,从而删除目标元素值,注意:数组和链表还不一样,数组元素值是连续寻址的,删除的实质是通过覆盖实现,链表是通过重新建立指针,回收旧址实现的。

#include<iostream>
#include<vector>
#include<cmath>
#include<string>

using namespace std;

class ArraySolution {
public:
	   int RemoveArrayelement(vector<int> array,int target) {
		int* fast = &array[0];
		//int* slow = &array[0];
		std::vector<int>::iterator it();
		while (std::vector<int>::iterator it != array.end())
		//	for (std::vector<int>::iterator it=array.begin(); it != array.end(); it++) {//在这里,it代表容器array里的元素值,相当于for循环里的数组元素索引,而不是for循环里的数组索引,使用it!=array.size()就会报错:
		//		//在这里,array.end()代表容器array里的最后一个元素
		//		//array.begin()代表容器array里的第一个元素
		//		if (*it != target) {
		//			
		//			slow++;
		//		}
		//		else if(*it == target) {	
		//			slow = *it;
		//		}else {
		//			return array;
		//		}
		//	}
		//	return array;
		//int fast = 0;
		int slow = 0;
		for (int fast = 0; fast < array.size(); fast++) {
			if (target != array[fast]) {
				array[slow++] = array[fast];
			}
		}
		return slow;
		
	}
	   
};
int main() {
	ArraySolution s1;
	vector<int>sums = { 1,2,4,4,5,6,4,8,9 };
	int target = 4;
	int result = s1.RemoveArrayelement(sums, target);
	cout << result;
	
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值