目录
一、异或运算的性质与拓展
异或的基本性质
设一个数为a,另一个个数为b,且a!=b;
则:
1)a^0==a
a^a==0
a^a^b==b
b^b^a==a
2)异或运算满足交换律和结合律
1、问题一:如何不使用额外变量交换两个数
int a;
int b;
a=a^b;//a=a^b
b=a^b;//b=a^b^b=a
a=a^b;//a=a^b^a=b
问题二:一个数组中有一个数出现了奇数次,其他数出现了偶数次,怎么找到这个数
分析:一个数出现了偶数次那么偶数次相同的数异或结果一定为0
一个数出现了奇数次那么奇数次相同的数异或结果一定为那个数
由上述可知代码为:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans=0;
for(int i=0;i<nums.size();i++)
{
ans^=nums[i];
}
return ans;
}
};
问题三:一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两种数
分析:一个数组中有两种数出现了奇数次设为a,b且a!=b,其他数都出现了偶数次,那么将数组中所有数的异或结果一定为设eor=a^b且不为0,则eor的二进制位中一定有一位是1,假设第8位是1,则a与b一定在第8位上不同,再设eor1,让eor1去异或数组中第8位不是1的数,那么eor1一定等于a或者b,则另一个一定为eor1^eor
那么我如何取出a与b的不同位呢?
假设eor=1010111100
~eor=0101000011
!eor+1=0101000100
eor&(~eor+1)=0000000100 ---->提取出最右侧的1
由上述可知代码为:
int eor=0;
for(int i=0;i<arr.length();i++)
{
eor^=arr[i];
}
//eor=a^b
//eor!=0
//eor必然有一个位置上是1
int rightOne=eor&(~eor+1);
int onlyOne=0;
for(int cur:arr){
if((cur&rightOne)==0){
onlyOne^=cur;
}
}
printf("%d",(eor^onlyOne));
二、二分的详解与扩展(简略版)
1、问题1:
在一个有序数组中,找到某个数是否存在
代码为:
class Solution {
public:
int search(vector<int>& nums, int target) {
int l=0,r=nums.size()-1;
while(l<=r)
{
int mid=(l+r)/2;
if(nums[mid]>target)
r=mid-1;
else if(nums[mid]<target)
l=mid+1;
else
return mid;
}
return -1;
}
};
2、问题2:
在一个有序数组中,找到>=某个数最左侧的位置
分析:先判定中点的位置是否大于等于num,如果满足则记录该位置,左侧依然可能存在>=num的数,所以继续二分,若终点位置不满足则右侧二分,若中点位置满足且比上一次记录位置更靠左,则放弃上一次记录位置,记录该位置,始终保持记录的是最左侧位置,一直到l<=r
题目链接:查找插入位置
代码为:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l=0,r=nums.size()-1;
int t=nums.size();//若数组中所有的数都小于目标数则直接返回最右侧坐标+1
while(l<=r)
{
int mid=(l+r)/2;
if(nums[mid]>target) r=mid-1,t=mid;
else if(nums[mid]<target) l=mid+1;
else return mid;
}
return t;
}
};
3、问题3:局部最小值问题
分析:先判断数组的头位置和尾位置是否满足局部最小,若满足则直接返回,若不满足则在该局部一定为局部减小,则[0,n-1]一定存在局部最小,直接取中点位mid,则若mid>mid-1则[0,m-1]一定存在局部最小,若mid<mid-1则[m,n-1]一定存在局部最小
代码为:
对数器测试题
public class Code04_BSAwesome {
//arr整体无序但满足相邻位置不相等
public static int oneMinIndex(int[] arr) {
if (arr == null || arr.length == 0) {
return -1;
}
int N = arr.length;
if (N == 1) {
return 0;
}
if (arr[0] < arr[1]) {
return 0;
}
if (arr[N - 1] < arr[N - 2]) {
return N - 1;
}
//二分法
int L = 0;
int R = N - 1;
//L~R范围需要三个数(不能两个数)
while (L < R - 1) {
int mid = (L + R) / 2;
if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) {
return mid;
} else {
//1、L > mid mid > R
//2、L < mid R > mid
//3、mid > L mid > R
if (arr[mid] > arr[mid - 1]) {
R = mid - 1;
} else {
L = mid + 1;
}
}
}
return arr[L] < arr[R] ? L : R;
}
//生成随机数组,且相邻数不相等
public static int[] randomArray(int maxLen, int maxValue) {
int len = (int) (Math.random() * maxLen);
int[] arr = new int[len];
if (len > 0) {
arr[0] = (int) (Math.random() * maxValue);
for (int i = 1; i < len; i++) {
do {
arr[i] = (int) (Math.random() * maxValue);
} while (arr[i] == arr[i - 1]);
}
}
return arr;
}
//验证方法
public static boolean check(int[] arr, int minIndex) {
if (arr.length == 0) {
return minIndex == -1;
}
int left = minIndex - 1;
int right = minIndex + 1;
//有难度
boolean leftBigger = left >= 0 ? arr[left] > arr[minIndex] : true;
boolean rightBigger = right < arr.length ? arr[right] > arr[minIndex] : true;
return leftBigger && rightBigger;
}
//打印输出
public static void printArray(int[] arr) {
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
}
public static void main(String[] args) {
int maxLen = 100;
int maxValue = 20;
int testTime = 1000000;
System.out.println("测试开始");
for (int i = 0; i < testTime; i++) {
int[] arr = randomArray(maxLen, maxValue);
int ans = oneMinIndex(arr);
if (!check(arr, ans)) {
printArray(arr);
System.out.println(ans);
break;
}
}
System.out.println("测试结束");
}
}
三、对数器的概念和使用
1、有一个你想要测的方法a
2、实现复杂度不好但是容易实现的方法b
3、实现一个随机样本产生器
4、把方法a和方法b跑相同的随机样本,看看得到的结果是否一样。
5、如果有一个随机样本使得比对结果不一致,打印样本进行人工干预,改对方法a或者方法b
6、当样本数量很多时比对测试依然正确,可以确定方法a已经正确。
Java版(以排序为例):
import java.util.Arrays;
public class A {
public static void selectionSort(int[] arr)
{
if(arr==null||arr.length<2)
{
return;
}
for(int i=0;i<arr.length;i++)
{
int minindex=i;
for(int j=i+1;j<arr.length;j++)
{
minindex=arr[j]<arr[minindex]?j:minindex;
}
swap(arr,i,minindex);
}
}
public static void swap(int[] arr,int i,int j)
{
int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
public static void comparator(int[] arr){
Arrays.sort(arr);
}
public static int[] generateRandomArray(int maxSize,int maxValue){
int[] arr=new int[(int)((maxSize+1)*Math.random())];
for (int i=0;i<arr.length;i++)
{
arr[i]=(int)((maxValue+1)*Math.random())-(int)(maxValue*Math.random());
}
return arr;
}
public static int[] copyArray(int[] arr)
{
if(arr==null)
{
return null;
}
int[] res=new int[arr.length];
for(int i=0;i<arr.length;i++){
res[i]=arr[i];
}
return res;
}
public static boolean isEqual (int[] arr1,int[] arr2){
if((arr1==null&&arr2!=null)||(arr1!=null&&arr2==null))
{
return false;
}
if(arr1==null&&arr2==null){
return true;
}
if(arr1.length!=arr2.length)
{
return false;
}
for(int i=0;i<arr1.length;i++){
if(arr1[i]!=arr2[i]){
return false;
}
}
return true;
}
public static void printArray(int[] arr){
if(arr==null){
return;
}
for(int i=0;i<arr.length;i++)
{
System.out.print(arr[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int testTime=500000;
int maxSize=100;
int maxValue=100;
boolean succeed=true;
for(int i=0;i<testTime;i++)
{
int[] arr1=generateRandomArray(maxSize,maxValue);
int[] arr2=copyArray(arr1);
selectionSort(arr1);
comparator(arr2);
if(!isEqual(arr1,arr2))
{
succeed=false;
break;
}
}
System.out.println(succeed?"Nice":"fucking fucked!");
int[] arr=generateRandomArray(maxSize,maxValue);
printArray(arr);
selectionSort(arr);
printArray(arr);
}
}
c++版:
#include<bits/stdc++.h>
using namespace std;
class Solution{
public:
static int reversePairs(vector<int>&nums){
auto L=0;
auto R=nums.size()-1;
auto res=0;
mergesort(nums,L,R);
return res;
}
static vector<int> mergesort(vector<int>&nums,int L,int R)
{
for(int i=0;i<=R;i++)
{
for(int j=i-1;j>=0;j--)
{
if(nums[j]>nums[j+1])
{
int t=nums[j];
nums[j]=nums[j+1];
nums[j+1]=t;
}
}
}
return nums;
}
};
vector<int> generateRandomVector(int maxsize,int value)
{
srand((int)time(NULL));
vector<int>result((rand()%(maxsize+1)));
for(auto i=0;i<result.size();i++)
{
result[i]=rand()%(value+1);
}
return result;
}
int main()
{
auto test_time=50000;
auto maxsize=10;
auto value=30;
auto if_accept=true;
for(auto i=0;i<test_time;i++)
{
vector<int>nums(generateRandomVector(maxsize,value));
vector<int>nums1(nums);
vector<int>nums2(nums);
sort(nums1.begin(),nums1.end());
Solution::reversePairs(nums2);
if(nums1!=nums2)
{
if_accept=false;
for(auto c:nums)
{
cout<<c<<" ";
}
break;
}
}
cout<<(if_accept?"nice!\n":"false!\n");
}
结束,撒花!!!