认识复杂度和简单排序

一、怎样评估某个算法的优劣

二、简单的排序算法

三、二分算法

四、题目总结

五、今日刷题

一、怎样评估某个算法的优劣

使用时间复杂度,但是时间复杂度不是值具体运行的时间,而是其操作的次数。
递归算法的时间复杂度的计算,使用的是主定理


二、简单的排序算法

1、选择排序
//选择排序
//逐渐有序,将0到n-1的最小值放到0位置上,1到n-1的最小值放到1位置上,依次最终完成排序
//时间复杂度为o(n^2)
int a[n];
int minpos;
for(int i = 0;i<n;++i)
{
for(int j = i+1;j<n-1;++j)
{
minpos = i;
if(a[j]<a[minpos])
minpos = j;
}
int tmp = a[i];
a[i] = a[minpos];
a[minpos] = tmp;
}

2、冒泡排序

//冒泡排序,将最大的值放到正确的位置
int a[n];
for(int i = 1;i<=n;++i)
{
for(int j = 0;j<n-i;++j)
{
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
}

3、插入排序

//插入排序,将值插入到正确的位置,逐步保证0到0有序,0到1有序,之后知道0到n有序
int a[n];
for(int i = 0;i<n;++i)
{
for(int j = i;j>0;--j)
{
if(a[j]<a[j-1])
swap(a[j],a[j-1]);
}
}

三、二分算法

求局部最小
思路:
说明二分不一定必须要求是有序的,只要求有某种特殊的要求即可。此题的具体求解是:首先考虑一下0位置和n-1位置上是不是局部最小,如果都不是,那么数组中间一定存在局部最小的数据。
在二分法求解中点的时候,一般使用的方法是:mid = (left+right)>>1,但是这样的写法可能存在数据溢出的情况,所以使用left+(right-left)>>1进行代替.
//局部最小问题的求解
int a[n];
if(a[0]<a[1])
retutn 0;
if(a[n-1]>a[n-2])
return n-1;
int left = 0;
int right = n-1;
int mid = 0;
while(left<right)
{
mid = left+(right-left)>>1;
if(a[mid]>a[mid-1])
right = mid;
else if(a[mid]>a[mid+1])
left = mid+1;
}
return mid;

四、题目总结

1、给定一个数组,求数组中任一位置的左边的最小值的下标和右边最小值的下标
思路一:对于给定的位置进行扫描,扫描左边和右边分别得到最小值,如果要求的所有位置的解,那么时间复杂度是O(N^2)。
思路二:进行预处理,使用两个数组,具体为数组A的位置i记录的是从0到i的最小值的下标,数组B的位置i记录的是从i到n-1位置的 最小值的下标。这两个数组的获得:数组A在扫描每个数的时候,如果前面的数比自己小,那么就等于前一个数的值,否则就是自己的位置,数组 B进行从后往前的扫描,进行同样的操作得到。此时的时间复杂度为O(N).
//求数组中某个位置的左边的最小值和右边的最小值
int num[n];
int a[n];
int b[n];
a[0] = 0;
b[n-1] = n-1;//a,b数组记录的是位置
for(int i = 1;i<n;++i)
{
if(num[i]<num[a[i-1]])
a[i] = i;
else
a[i] = a[i-1];
}
for(int i = n-2;i>=0;--i)
{
if(num[i]<num[a[i+1]])
b[i] = b[i+1];
else
b[i] = i;
}
//那么查询的时候直接输出a和b数组相应位置上的数就可以了

2、异或运算的应用

  • 异或运算就是无进位相加,从这个角度可以更容易理解异或运算的交换律和结合律
  • n^n = 0;n^0 = n
  • 使用异或来进行交换:
//要求a,b在内存中不是同一块东西,否则就会将其置为0
int a;
int b;
//交换a与b的值
a = a^b;
b = a^b;
a = a^b;
  • 提取出一个数最右边的1:x&(-x)或者是x&(~x+1),最终得到的是一个数的最右边的1

  • 五、今日刷题

    题目:
    给定某二叉树的中序和前序遍历的结果,恢复该二叉树
    思路:在根据遍历的顺利恢复二叉树的时候,中序的顺序是不能少的,若只有前序和后序那么是不能恢复出二叉树的顺序的。
    具体的做法是根据前序和后序得到树的根,然后在中序的序列中找到左子树部分和右子树部分,然后建立左子树和右子树得到最后的结果。
    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* build(vector<int> pre,vector<int> vin,int prel,int prer,int vinl,int vinr)
        {
            //首先得到根结点
            TreeNode* root = new TreeNode(pre[prel]);//根结点
            if(prel==prer)
                return root;
            int pos;//找出根结点的位置
            for(int i = vinl;i<=vinr;++i)
            {
                if(vin[i]==pre[prel])
                {
                    pos = i;
                    break;
                }
            }
            int llen = pos-vinl;
            int rlen = vinr-pos;
            if(llen>0)//建立左孩子
            {
                TreeNode* leftchild = build(pre,vin,prel+1,prel+llen,vinl,pos-1);
                root->left = leftchild;
            }
            if(rlen>0)
            {
                TreeNode* rightchild = build(pre,vin,prel+llen+1,prer,pos+1,vinr);
                root->right = rightchild;
            }
            return root;
            
        }
        TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
           //前序遍历确定的是根结点,根据根结点在中序遍历的位置分出左右子树分贝进行建树
            int prelen = pre.size();
            int vinlen = vin.size();
            if(prelen==0)
                return NULL;
            else
            {
                TreeNode* root = build(pre,vin,0,prelen-1,0,vinlen-1);
                return root;
            }
        }
    };
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值