左程云算法课—01课程笔记

目录

一、异或运算的性质与拓展

异或的基本性质

二、二分的详解与扩展(简略版)

三、对数器的概念和使用

Java版(以排序为例):

c++版:


一、异或运算的性质与拓展

异或的基本性质

设一个数为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");
}

结束,撒花!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值