B站左程云算法视频高级班05

题目一:在一个无序数组中,求第k小的数

快排:荷兰国旗问题

BFPRT 有讲究的选择一个数

之后的步骤和快排一样

假设整个方法叫f函数 f(arr, k)

1)0~4一组 5~9一组 0~14一组 剩下的一组

2)marr[a,b,c,d,……]  每组选一个中位数 O(N)

3)求marr的中位数 N/5   f(marr, marr/2)   -> x

即估计大于等于x的数至少有多少个 

 1)分组  O(1)

2)组中中位数 O(N)

3)f(marr, marr.length/2) 得出x T(N/5)

4)小于x 等于x 大于x O(N)

5)T(7N/10)

时间复杂度为O(N)

//在arr[begin..end]范围上,求如果排序的话,i位置的数是谁,返回
//i一定在begin~end范围上
public static int select(int[] arr, int begin, int end, int i){
    if(begin == end){
        return arr[begin];
    }
    //分组 + 组内排序 + 组成newarr + 选出newarr的上中位数 pivot
    int pivot = medianOfMedians(arr, begin, end);
    //根据pivot做划分值 <p ==p >p ,返回等于区域的左边界和有边界
    //pivotRange[0] 等于区域的左边界
    //pivotRange[1] 等于区域的右边界
    int[] pivot = partition(arr, begin, end, pivot);
    if(i >= pivotRange[0] && i <= pivotRange[1]){
        return arr[i];
    }else if(i < pivotRange[0]){
        return select(arr, begin, pivotRange[0] - 1, i);
    }else {
        return select(arr, pivotRange[1] + 1, end, i);
    }
}

public static int medianOfMedians(int[] arr, int begin, int end){
    int num = end - begin + 1;
    int offset = num % 5 == 0 ? 0 : 1;
    int[] mArr = new int[sum / 5 + offset];
    for(int i = 0; i < mArr.length; i++){
        int beginI = begin + i * 5;
        int endI = beginI + 4;
        mArr[i] = getMedian(arr, beginI, Math.min(end, endI));
    }
    return select(mArr, 0, mArr.length - 1; mArr.length / 2);
}

public static int[] partition(int[] arr, int begin, int end, int pivotValue){
    int small = begin - 1;
    int cur = begin;
    int big = end + 1;
    while(cur != big){
        if(arr[cur] < pivotValue){
            swap(arr, ++small, cur++);
        }else if(arr[cur] > pivotValue){
            swap(arr, cur, --big);
        }else{
            cur++;
        }
    }
}

题目2:给定一个正数1,裂开的方法有1种,给定一个正数2,裂开的方法 1和1 、 2

3,裂开的方法有三种(1、1、1)、(1、2)、(3)

不降序裂开

//pre裂开的前一个部分
//rest还剩多少值,需要去裂开,要求裂出来的第一部分,不要比pre小
//返回裂开的方法数
public static int process(int pre, int rest){
    if(rest == 0){
        return 1;//之前裂开的方案,构成了一种有效方法
    }
    if(pre > rest){
        return 0;
    }
    int ways = 0;
    for(int i = pre; i <= rest; i++){//i:rest第一个裂开的部分,值是多少
        ways += process(i, rest - i);
    }
    return ways;
}

public static int ways2(int n){
    if(n < 1){
        return 0;
    }
    int[][]dp = new int[n + 1][n + 1];
    for(int pre = 1; pre < dp.length; pre++){
        dp[pre][0] = 1;
    }
    for(int pre = n; pre > 0; pre--){
        for(int rest = pre; rest <= n; rest++){
            for(int i = pre; i <= rest; i++){
                dp[pre][rest] += dp[i][rest - i];
            }
        }
    }
    return dp[1][n];
}

 

public static int ways3(int n){
    if(n < 1){
        return 0;
    }
    int[][]dp = new int[n + 1][n + 1];
    for(int pre = 1; pre < dp.length; pre++){
        dp[pre][0] = 1;
    }
    for(int pre = 1; pre < dp.length; pre++){
        dp[pre][pre] = 1;
    }
    for(int pre = n - 1; pre > 0; pre--){
        for(int rest = pre + 1; rest <= n; rest++){
            dp[pre][rest] += dp[pre + 1][rest] + dp[pre][rest - pre];
        }
    }
    return dp[1][n];
}

题目3:给定一棵二叉树的头节点head,已知所有节点的值都不一样,返回其中最大的且符合搜索二叉树条件的最大拓扑结构的大小

拓扑结构:不是子树,只要能连起来的结构都算。

 时间复杂度O(N)

题目4:给定一个长度为偶数的数组arr,长度记作2*N,前N个为左部分,后N个为右部分

arr可以表示为{L1,L2,……,Ln,R1,R2,……,Rn}

请调整为{R1,L1,R2,L2......Rn,Ln}的样子

(完美洗牌)

a        b        c        d        e        f

0        1        2        3        4        5

L1     L2       L3      R1     R2      R3

[a        d        b        e        c        f]

i小于等于N     i大于N

i左半区            右半区

2*i                    2(i-N) - 1

下标循环对,可能存在多个不相交的小环

N(偶数)

当N = 3^k - 1

存在的结论:不同环的触发点:1,3,9....3^(k-1)

N=普通偶数时

……a b c d e 甲乙 ……

左组内部逆序,乙组内部逆序,整体逆序

……甲乙abcde……

假设N = 14,左7,右7

L1L2L3L4L5L6L7R1R2R3R4R5R6R7

14最接近8

先让L1L2L3L4R1R2R3R4调整

L5L6L7R1R2R3R4逆序

调整完后变成L1L2L3L4R1R2R3R4L5L6L7R5R6R7

再逆序变成R1R2R3R4L1L2L3L4L5L6L7R5R6R7

剩下6,接近2,重复……

拓展:数组无序时候,

调整为[a    b    c    d   e  f   g   h  i  ……]

使得关系为小于等于和大于等于交错

1)arr 排序(堆排)

N=偶数

L1L2……LiR1R2……Ri

从小到大

调整为R1L1R2L2……RiLi

接着L1R1R2L3……

N=奇数

L0L1L2……LiR1R2……Ri

调整为L0R1L1R2L2……RiLi接着如上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法数据结构涵盖了以下主要内容: 数据结构(Data Structures): 逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值