1、调整数组顺序使奇数位于偶数前面
1.1题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示列:
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
提示:
1 <= nums.length <= 50000
1 <= nums[i] <= 10000
1.2题目分析
方法一:利用快慢指针
- 定义两个指针low和fast,都从下标为0的位置开始
- 只要fast没有数组越界,fast指针一直向前遍历
- 遇到low指针的元素是偶数并且fast指向的元素是奇数就交换这两个指针所指向的值
- 只有遇到low指向的元素不是偶数的时候,low指针才往前遍历
以例子数组【1234】来说,具体的过程如下:
代码实现:
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
vector<int> exchange(vector<int>& nums)
{
int low = 0;
int fast = 0;
while (fast < nums.size())
{
if (nums[low] % 2 == 0 && nums[fast] % 2 != 0)
{
swap(nums[low], nums[fast]);
}
if (nums[low] % 2 != 0)
{
low++;
}
fast++;
}
return nums;
}
方法二:双指针
- 定义两个指针low和high。low从数组的头部开始找偶数,high从数组的尾部开始找奇数
- 直到low>=high时退出寻找
代码实现:
vector<int> exchange1(vector<int>& arr)
{
int low = 0;
int high = arr.size() - 1;
while (low < high)
{
if (arr[low] % 2 != 0)
{
low++;
continue;
}
if (arr[high] % 2 == 0)
{
high--;
continue;
}
swap(arr[low], arr[high]);
}
return arr;
}
int main()
{
vector<int> res;
vector<int> a;
res.push_back(1);
res.push_back(2);
res.push_back(3);
res.push_back(4);
a = exchange1(res);
for (int i = 0; i < a.size(); i++)
{
cout << a[i] << endl;
}
return 0;
}
2、在排序数组中查找数字|
1、题目要求
统计一个数字在排序数组中出现的次数。
示例1
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例2
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
2、题目分析
方法一:挨个遍历查询
这样做的时间复杂度最高,可达O(n)
int search(vector<int>& nums, int target)
{
int count = 0;
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] == target)
count++;
}
return count;
}
方法二:巧用二分查找
基于上一个方法时间复杂度太高,并且没有充分利用数组排序的特点,所以采用二分查找的方式来求解,时间复杂度是O(logn)
- 定义两个指针,low指向数组的头部,high指向数组的尾部
- 利用二分查找的方式,判断数组中间mid所指的数字是否和目标元素相同
- 如果相同的话,利用数组排序的特点,目标元素的相邻元素一定和目标元素是相同的,分别在左右子数组中统计和目标数字相同的数字个数Lcount和Rcount
- 最后返回值为Lcount+Rcount+1
具体的,以下面以 nums = [5,7,7,8,8,10], target = 8这个例子加以分析
注意!!
还有特殊情况的处理,如果数组中没有元素应该return -1
int search1(vector<int>& arr, int target)
{
if (arr.size() == 0)
{
return -1;
}
int low = 0;
int high = arr.size() - 1;
int countL = 0;
int countR = 0;
int count = 0;
while (low <= high)
{
int mid = (high - low + 1) / 2 + low;
if (arr[mid] < target)
low = mid + 1;
else if (arr[mid] > target)
high = mid - 1;
else//找到了,因为是排序数组,则相同的元素就在该元素的左右两边
{
int Lhigh = mid ;
int Rlow = mid ;
while (Lhigh > low&& arr[--Lhigh] == target)
{
countL+=1;
}
while (Rlow < high && arr[++Rlow] == target)
{
countR+=1;
}
count = countL + countR + 1;
break;
}
}
return count;
}
3、0~n-1中缺失的数字
1、题目要求
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例1:
输入: [0,1,3]
输出: 2
示例2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8
限制:1 <= 数组长度 <= 10000
2、题目分析
注意!
:[0,1]表示数组长度为n-1=2,所以n=3,共有3个数字,所以在{0,3}之间的是[0,1,2];不能理解为只有2个数字,不缺失数字。这一点很重要。
方法一:两次循环
- 第一次循环得到0~n-1的总和sum1,第二次循环得到数组元素的总和sum2
- 返回sum1-sum2,即为缺失的那个数
- 但是这种方法不可取,时间复杂度太高,没有充分利用数组有序的特点
代码实现:
int missingNumber(vector<int>& arr)
{
if (arr.size() == 0)
return -1;
int sum1 = 0;
int sum2 = 0;
for (int i = 0; i <= arr.size(); i++)
{
sum1 += i;
}
for (int j = 0; j < arr.size(); j++)
{
sum2 += arr[j];
}
return sum1 - sum2;
}
方法二:一次循环
- 根据数组排列有序的特点。没有缺失的数字一定是和其下标一一对应的
- 如果遇到没有对应的数字则表示该下标对应的数字缺失
- 如果数组遍历完毕都没找到缺失的数字,说明是数组最后一个数字缺失。返回arr.size()的值
代码实现如下:
int missingNumber1(vector<int>& arr)
{
for (int i = 0; i < arr.size(); i++)
{
if (i != arr[i])
return i;
}
return arr.size();
}
方法三:二分查找
-
二分查找的思路还是根据下标和数组中的值来判断缺失元素。但是相比于方法三更好的是一次可以舍弃一半的数据
-
如果==mid等于arr[mid]==的值相等的话,表示在mid之前都是按照顺序没有缺失存放的,那么就在后半边数组中去寻找,high = mid+1.
-
如果mid和arr[mid]的值不相等的话。比较mid-1和arr[mid-1]的值是否相等
3.1如果相等就表示mid即为缺失的数字
3.2如果不相等,则表示缺失的值,在mid前面。让high = mid-1 -
查找到最后返回值的探讨。返回值不应该是mid。比如下面这个例子
所以二分查找跳出循环过后需要返回low,而不是mid.
代码实现如下:
int missingNumber2(vector<int>& arr)
{
if (arr.size() == 0)
return -1;
int low = 0;
int high = arr.size() - 1;
while(low <= high)
{
int mid = (high - low + 1) / 2 + low;
if (mid == arr[mid])//左半部分没有问题
{
low = mid + 1;
}
else//左半部分有问题
{
if (low > 0 && mid - 1 == arr[mid - 1])
return mid;
else
high = mid - 1;
}
}
return low;
}
int main()
{
vector<int> res;
res.push_back(0);
res.push_back(1);
res.push_back(2);
res.push_back(3);
res.push_back(4);
res.push_back(5);
cout << missingNumber2(res) << endl;
return 0;
}