一、怎样评估某个算法的优劣
二、简单的排序算法
三、二分算法
四、题目总结
五、今日刷题
一、怎样评估某个算法的优劣
使用时间复杂度,但是时间复杂度不是值具体运行的时间,而是其操作的次数。递归算法的时间复杂度的计算,使用的是主定理
二、简单的排序算法
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; } } };