数据结构与算法学习笔记(基础班一)---复杂度

选择排序

时间复杂度O(n^2) 空间复杂度 O(1) 稳定

  • 0 - n-1 选择一个最小的排在0号位置
  • 1 - n-1选择一个最小的排在1号位置
  • 2 - n -1选择一个最小的排在2号位置
    ...
    以此类推,代码如下:
public class SelectSort {
  public static void selectSort(int[] arr){
        if(arr == null || arr.length < 2){
            return;
        }
        // 从0到n-1选一个最小的
        // 从1到n-1选一个最小的
        for(int i = 0;i < arr.length;i++){
            // 每次最小值都默认为起始元素
            int minIndex = i;
            for(int j = i+1;j < arr.length;j++){
                // 找到每一轮中的最小值
                minIndex = arr[minIndex] > arr[j] ? j : minIndex;
            }
            // 让最小值到每轮开头的位置
            swap(arr,minIndex,i);
        }
    }
    private static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

冒泡排序

时间复杂度O(n^2) 空间复杂度O(1) 稳定

 public static void maoPao(int[] arr){
        if(arr == null || arr.length < 2){
            return;
        }
        // 两两交换 最大的往后沉
        int n = arr.length;
        for (int i = n -1; i >=0; i--) {
            for (int j = 0; j < i; j++) {
                if(arr[j] > arr[j + 1]){
                    swap(arr,j,j+1);
                }
            }
        }
    }
    public static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

插入排序

时间复杂度O(n^2) 空间复杂度O(1) 稳定

 public static void insertSort(int[] arr){
        if(arr == null || arr.length < 2){
            return;
        }

        int n = arr.length;
        for (int i = 0; i < n; i++) {
            for(int j = i;j > 0 && arr[j] < arr[j -1];j--){
                swap(arr,j,j-1);
            }
        }
    }

    private static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

二分

  • 在一个有序数组中找一个数是否存在。
  • 在一个有序数组中,找>=某个数最左侧的位置。
  • 在一个有序数组中,找<=某个数最右侧的位置。
  • 局部最小值问题。
  1. 有序数组二分
public static boolean isE(int[] arr,int target){
        if(arr == null || arr.length == 0){
            return false;
        }
        int L = 0;
        int R = arr.length-1;
        while(L <= R){
            int mid = L + ((R -L) >>1);
            if(arr[mid] == target){
                return true;
            }else if(arr[mid] > target){

                R = mid - 1;
            }else{
                L = mid + 1;
            }
        }
        return false;
    }
  1. // 有序数组中寻找 大于等于目标值最左侧位置
 public static int findLeftNum(int[] arr, int target){
        if(arr == null || arr.length <=0){
            // 负一时没有
            return -1;
        }

        int index = -1;

        int L = 0;
        int R = arr.length-1;
        while (L <= R){
            int mid = L + ((R - L) >>1);
            if(arr[mid] >= target){
                index = mid;
                R = mid - 1;
            }else{
                L = mid + 1;
            }
        }
        return index;
    }
  1. // 寻找小于等于目标值最右侧的位置
public static int findRightNum(int[] arr,int target){
        if(arr == null || arr.length <= 0){
            return -1;
        }
        int L = 0;
        int R = arr.length - 1;
        int index = -1;
        while(L <= R){
            int mid = L + ((R - L)>>1);
            if(arr[mid]<= target){
                index = mid;
                L = mid + 1;
            }else{
                R = mid - 1;
            }
        }
        return index;
    }
  1. // 局部最小值,在无序数组中返回一个局部最小值的位置
public static int findMinNum(int[] arr){
        if(arr == null || arr.length <= 1){
            return -1;
        }

        int L = 0;
        int R = arr.length - 1;
        if(arr[0] < arr[1]){
            return 0;
        }
        if(arr[R] < arr[R -1]){
            return R;
        }

        // 前面都不满足则一定存在局部最小值在中间
        while(L <= R){
            // 先判断首位元素是否满足要求
            int mid = L + ((R - L)>>1);
            if(arr[mid] < arr[mid-1] && arr[mid] < arr[mid +1]){
                return mid;
            }else if(arr[mid] > arr[mid -1]){
                R = mid - 1;
            }else{
                L = mid + 1;
            }

        }

        return -1;
    }

异或运算

  • 无进位相加
  • 0 ^ N = N N ^ N = 0
  • 满足交换律和结合律
  • 交换两个值
// 交换a ,b的值,内存要独立
int a = 1;
int b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
  1. 一个数组中有一种数出现了奇数次,其余数都是偶数次,找出这个数。(利用异或运算,计算性质,N ^ N=0,交换律结合律,偶数次的数字最终会全部消掉,剩下奇数次的数)。
 public static int getNum(int[] arr){
        int eor = 0;
        for(int item : arr){
            eor ^= item;
        }
        return eor;
    }

提取一个数最右边的1

int n =2;
int res = n &(~n+1); // 等价于 n & (-n)

  1. 一个数组中,有两个数出现了奇数次,其余都出现了偶数次,找出这两个数。
    • 由于只有两个数出现了基数次,不妨设出现奇数次的两个数分别为 a,b则由题意可得,
      所有数异或起来可得eor = a ^ b且不等于0,则必存在a,b中至少有一位不相等,假设a,b中第八位不同时相等,a 中第八位为1,b中第八位为0,则,数组可以分成两部分,第八位为1的(a),和第八位为0的(b),让a堆所有数异或,则最后会剩下一个奇数,则求出了一个奇数,另一个奇数就好求了。
 public static int[] getNum(int[] arr){
        if(arr == null || arr.length == 0){
            return new int[0];
        }
        int eor = 0;
        // 求a , b的异或值
        for(int item : arr){
            eor ^= item;
        }
 
        // 求出 eor中最右边的1
        int rightOne = eor & (-eor);
        int eor2 = 0;
        for(int item : arr){
            if((item & rightOne) != 0){
                // item中此位位1
                eor2 ^= item;
            }
        }
        // 一个奇数位eor2 ,则另一个位eor ^ eor2
        return new int[]{eor2,eor2^eor};
    }
  1. 一个数组arr中有一种数出现K次,其他数都出现了M次,
    M > 1, K < M
    找到,出现了K次的数,
    要求,额外空间复杂度O(1),时间复杂度O(N)
  • 思路:
    • 如果是int 型数组,申请一个大小为32的int型数组t,统计arr中所有的数的二级制为出现的次数放入t中
    • 用遍历t,判断t中每一个元素能否被M整除(取模),能被整除说明统计的都是出现M次的数字贡献的,此时出现K次的数的该位置是0,不能整除,出现K次的数的该位置二进制是1。
    public static int mM(int[] arr, int k, int m) {
        if (k >= m) {
            return -1;
        }

        // 统计所有数每个位上的次数
        int[] t = new int[32];

        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < 32; j++) {
                t[j] += ((arr[i] >> j) & 1);
            }
        }

        // t中每一位和m取模,如果刚好无余数,则该为的1不是k中的数贡献的
        int res = 0;
        for (int i = 0; i < 32; i++) {
            if (t[i] % m != 0) {
                res |= 1 << i;
            }
        }
        return res;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容