补充说明:
异或(^)可以理解为无进位相加(可解释异或的交换性质)。
0^1=1
1^1=0
0^0=0
a = 1^5^2^3^5^5^3^2^2^1^3^4
= 1^1^2^2^2^3^3^3^4^5^5^5
= 2^3^4^5
不用额外变量交换两个数
void swap(int& a,int& b){
a=a^b; // a = a^b b = b
b=a^b; // a = a^b b = (a^b)^b
a=a^b; // a = (a^b)^(a^b^b) b = (a^b)^b
}
注意:用异或运算可以省空间(无需中间变量),但要求两个变量在不同的内存空间里,否则会变成零
题目 :一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数?
思路分析:利用异或运算,计算性质,N ^ N=0,交换律结合律,偶数次的数字最终会全部消掉,剩下奇数次的数
void printOddTimesNum(vector array) {
int arrLen = array.size();
int eor = 0;
for (int i = 0; i < arrLen; i++) {
eor ^= array[i];
}
cout << eor << endl;
}
题目 :一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
思路分析:由于只有两个数出现了奇数次,不妨设出现奇数次的两个数分别为 a , b
则由题意可得,所有数 异或起来可得 eor = a ^ b 且不等于0 ,则必存在a,b(二进制)中至少有一位不相等,
假设 a,b 中第6位(最右边)不同,且 a 中第6位为1,b 中第6位为0,则 eor 的 第6位(最右边)为1,
提取 eor 最右边的 1 (二进制数) 为 rightOne (0000 0100),
然后根据第6位是否为 1 (rightOne),可以将给定数组分成两堆,第6位为1的(含a堆)和第6位为0的(含b堆) ,
将含a堆的所有数异或,偶数次的数 异或 依然为0,因此得到其中一个奇数 onlyOne = a
另一个奇数 otherOne = eor ^ onlyOne = (a ^ b) ^ a = b
void printOddTimesNum(vector& array) {
// 假设数目为奇数的两种,分别为啊 a ,b
int arrLen = array.size();
int eor = 0;
for (int i = 0; i < arrLen; i++) {
eor ^= array[i];
}
// eor = a ^ b;
int rightOne = eor & (~eor + 1); // 提取eor最右边的1
int onlyOne = 0;
for (int i = 0; i < arrLen; i++) {
if ((array[i] & rightOne) != 0) {// 将数组分成两堆
onlyOne ^= array[i];
}
}
// onlyOne = a | b;
int otherOne = eor ^ onlyOne;
cout << onlyOne << "\t" << otherOne << endl;
}
提取一个数最右边的1 :
res = n &(~n+1);
例:0100 0110(70) ----> 0000 0010(2)
int n = 70;
int res = n &(~n+1); // res = 2
题目:在一个有序数组中找一个数是否存在。
bool isExist(vector& array,int target){
int arrLen = array.size();
int L = 0;
int R = arrLen - 1;
while(L <= R){
int mid = L + ((R -L) >> 1);
if(array[mid] == target){
return true;
}
if(array[mid] > target){
R = mid - 1;
}else{
L = mid + 1;
}
}
return false;
}
题目:在一个有序数组中,找>=某个数最左侧的位置。(或者找<=某个数最右侧的位置)
int findLeftNum(vector& array, int target) {
int index = -1;
int arrLen = array.size();
int L = 0;
int R = arrLen - 1;
while (L <= R) {
int mid = L + ((R - L) >> 1);
if (array[mid] >= target) {
index = mid;
R = mid - 1;
}
else {
L = mid + 1;
}
}
return index;
}
int findRightNum(vector& array, int target) {
int index = -1;
int arrLen = array.size();
int L = 0;
int R = arrLen - 1;
while (L <= R) {
int mid = L + ((R - L) >> 1);
if (array[mid] <= target) {
index = mid;
L = mid + 1;
}
else {
R = mid - 1;
}
}
return index;
}
题目:局部最小值问题。(数组A无序,相邻数一定不相等,找一个局部最小值)
int findMinNum(vector& array) {
int arrLen = array.size();
int L = 0;
int R = arrLen - 1;
if (array[0] < array[1]) {
return 0;
}
if (array[R] < array[R - 1]) {
return R;
}
// 前面都不满足则一定存在局部最小值在中间
while (L <= R) {
// 先判断首位元素是否满足要求
int mid = L + ((R - L) >> 1);
if (array[mid] < array[mid - 1] && array[mid] < array[mid + 1]) {
return mid;
}
// 这里位置替换和普通二分法不一样
// 不可以用 R = mid - 1;L = mid + 1; 来更新边界位置,会发生越界
// 例如 数组大小为6的时候 {1, -5, 2, 10, 6, -3}
// L=0,R=5 -> mid=2 更新后 L=0,R=1 -> mid=0
// 存在条件判断 array[mid - 1] 就会越界
else if (array[mid] > array[mid - 1]) {
R = mid;
}
else {
L = mid;
}
}
return -1;
}
随机Vector
头文件 RandomArray.h
#pragma once
#include
using namespace std;
#include
class RandomArray {
public:
//声明静态成员函数
static void generateRandomArray(vector& randomArray, int maxSize, int maxValue);
static void printArrayInfo(vector array);
};
源文件 RandomArray.cpp
#include "RandomArray.h"
void RandomArray::generateRandomArray(vector& randomArray, int maxSize, int maxValue) {
if (!randomArray.empty()) {
randomArray.clear();
}
int randomSize = rand() % (maxSize + 1) + 1; // 生成 1~maxSize 之间的一个随机整数
randomArray.resize(randomSize);
for (int i = 0; i < randomSize; i++) {
int randomValue = (rand() % (maxValue + 1)+1) - (rand() % (maxValue + 1));
randomArray[i] = randomValue;
}
}
void RandomArray::printArrayInfo(vector array) {
int arraySize = array.size();
for (int i = 0; i < arraySize; i++) {
cout << array[i] << " ";
}
cout << endl;
}
时间复杂度O(n2)
,额外空间复杂度O(1)
// 选择排序不适合使用 异或 来互换值
// array[i], array[minIndex] 有可能指向同一个内存空间 , 异或结果会为0
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void selectionSort(vector& array) {
for (int i = 0; i < array.size() - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < array.size(); j++) {
minIndex = array[j] < array[minIndex] ? j : minIndex;
}
swap(array[i], array[minIndex]);
}
}
时间复杂度O(n2)
空间复杂度O(1)
稳定
void swap(int& a, int& b) {
a = a ^ b; // a = a^b b = b
b = a ^ b; // a = a^b b = (a^b)^b
a = a ^ b; // a = (a^b)^(a^b^b) b = (a^b)^b
}
void bubbleSort(vector& array) {
for (int i = 0; i < array.size() - 1; i++){
for (int j = 0; j < array.size() - 1 - i; j++){
if (array[j] > array[j + 1]){
swap(array[j], array[j + 1]);
}
}
}
}
时间复杂度O(n2)
空间复杂度O(1)
稳定
void swap(int& a, int& b) {
a = a ^ b; // a = a^b b = b
b = a ^ b; // a = a^b b = (a^b)^b
a = a ^ b; // a = (a^b)^(a^b^b) b = (a^b)^b
}
void insertSort(vector& array) {
for (int i = 1; i < array.size(); ++i){
for (int j = i-1; j >= 0 && array[j] > array[j + 1]; j--){
swap(array[j], array[j + 1]);
}
}
}