练习

sizeof求字符串长度时包含"\0"

正数的补码是他本身,负数的补码是其相应正数取反码加1。

假设有一个 int 类型的数,值为5,那么,我们知道它在计算机中表示为:

00000000 00000000 00000000 00000101

5转换成二制是101,不过int类型的数占用4字节(32位),所以前面填了一堆0。

比如:00000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。

那么,补码为:

11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011


所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。


有36辆自动赛车和6条跑道,没有计时器的前提下,最少用几次比赛可以筛选出最快的三辆赛车?
36车分6组,每次取前三,并标记顺序,决出18辆车,18分3组,6组的第一名是一组,第二名是一组,第三名是一组。第一名这组先比赛,可以决出前3,然后将前三的第一名出列,现在只差第二名和第三名,从第一名其相应队伍中拿出后两名,再从第二名队伍中拿出他的第二名。第三名队伍中的所有剩下的车都没有希望。(第二名和第三名只会从这五个车中产生),这样取前两名就得到所求。总共需要6+1+1=8次

 一个系统,提供多个http协议的接口,返回的结果Y有json格式和jsonp格式。Json的格式为{"code":100,"msg":"aaa"}, 为了保证该协议变更之后更好的应用到多个接口(工厂方法:根据请求的不同,调用不同的方法,返回不同的类型对象),为了保证修改协议不影响到原先逻辑的代码(适配器),以下哪些设计模式是需要的?协议的变更指的是日后可能返回xml格式,或者是根据需求统一对返回的消息进行过滤(装饰者:是用来动态添加功能的,就是过滤 消息,比如非法字符&&&之类的,消息过长之类 )。


 适合并行处理的排序算法是() 基数排序

并行处理也就是将大的数据分块,每个执行流处理一块,然后合并,之后再分块,基数排序可以做到这样


枚举排序,通常也被叫做秩排序,算法基本思想是:对每一个要排序的元素,统计小于它的所有元素的个数,从而得到该元素在整个序列中的位置,时间复杂度为O(n^2)


下述二叉树中,哪一种满足性质:从任一结点出发到根的路径上所经过的结点序列按其关键字有序()

一:二叉排序树的左子树节点值都小于根节点值,右子树节点值都大于根节点,因此假如根节点值为10,其左节点值为5,其左节点的右节点值为8,那么从右节点到跟节点的值依次为8  5  10,显然不是有序的
二:哈夫曼树是带权路径最小的二叉树,也不是
三:AVL树是二叉排序树,只不过其左右子树的高度差有限制,在1之内,由一只非有序
四:堆是一种完全二叉树,其有大顶堆和小顶堆的分别,大顶堆是指其每个节点的值都大于其左右孩子的值(小顶堆反之),因此从任一节点到根节点是升序排列的(小顶堆反之)

非线性结构是指在该类结构中至少存在一个数据元素,它具有两个或者两个以上的前驱或后继.如树和二叉树等.

做题目时,注意初始化局部变量,修改字符串后,字符串结尾符要写上。


注意循环条件的判断。这个容易错。

在用二分法求某一个数第一次出现的时候,一定要注意我们做判断的时候数组的越界。因为我们这里有对mid进行改变,所以有必要对其进行合法性的再次判断。
if(arr[mid]==k){
    if((mid-1>=0&&arr[mid-1]!=k)||mid-1==0)
         return mid;
    else
         end = mid-1;
}

判断一棵树是否是平衡的:
这个采用递归,首先判断子树的平衡性由子树的深度得出这个树是否是平衡的。
要做到先子树后本树,我们必须加一个参数用于保存树的深度,因为当两个子树都是平衡的,然后在判断本树是否平衡的时候,我们需要两个子树的深度来判断。因为我们要把深度传给调用者,所以得采用传指针的方式。失误的地方:if后面没有{}导致return永远执行。注意这里是递归调用,在局部变量中申请两个变量用于存储返回值。
class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
		int depth = 0;
        return IsBalanced(pRoot,&depth);
    }
    bool IsBalanced(TreeNode*proot,int *depth){
        if(proot==NULL){
            *depth=0;
            return true;
        }
        int left = 0,right = 0;
        if(IsBalanced(proot->left,&left)&&IsBalanced(proot->right,&right)){
            if((right-left<=1)&&(right-left>=-1)){//注意这里
                *depth = left>right?(left+1):(right+1);
            	return true;
            }<span style="font-family: Arial, Helvetica, sans-serif;">//注意这里</span>

        }
        return false;
    }
};

数组中只出现一次的数字,注意问题*num1和*num2的初始化,还有忘记了提前返回的return和默认的错误输出是什么。树上的做法是,当输入不符合要求时,直接返回,并没有对输入做修改。
class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
<span style="white-space:pre">		</span>int result = 0;
        *num1=0;
        *num2=0;
        if(data.size()>1){
            vector<int>::iterator data_begin = data.begin();
            while(data_begin!=data.end()){
                result^=*data_begin;
                data_begin++;
            }
            int n = GetFirstBit(result);
            data_begin = data.begin();
            while(data_begin!=data.end()){
                if(IsBit1(*data_begin,n)){
                    *num1=*num1^*data_begin;
                }else{
                    *num2=*num2^*data_begin;
                }
                
                data_begin++;
            }
            return;//这里忘记了
        }
        *num1=0;//默认错误输出
        *num2=0;//<span style="font-family: Arial, Helvetica, sans-serif;">默认错误输出</span>

        return; 
    }
    int GetFirstBit(int num){
        int n = 0;
        while((num & (0x1<<n++))==0){
            
        }
        return n-1;
    }
    bool IsBit1(int num,int n){
        num=num>>n;
        if(num&0x1){
            return true;
        }
        return false;
    }
};

输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。 注意:每一种情况都要有return;
class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> &array,int sum) {
        vector<int> result;
        int length = array.size();
        if(length < 2){
            return result;
        }
        int start = 0;
        int end = length -1;
        while(start<end){
            int cursum = array[start]+array[end];
            if(cursum==sum){
                result.push_back(array[start]);
                result.push_back(array[end]);
                return result;
            }else if(cursum>sum){
                end--;
            }else{
                start++;
            }
        }
        return result;//刚开始忘了,老是导致溢出,这个已经犯了好几次类似错误了。
    }
};

和为S的所有正整数序列:
因为我们要得到下标区间,所以不必对区间进行重复计算,所以我们让区间单向增加。大循环主要是增加big,在一定条件下增加small。然后small的操作又是在一个循环中。每次修改边界时都需要做判断,以决定是否还执行循环。
我们每次得到的结果是一个区间,所以要统计这个区间的值,所以得有两个下标,然后我们还得有一个用于控制循环的终止的下标。因为控制循环终止的下表是一直增加的。这里与以前编程所不同的就是,我们并不是每次都修改用于循环终止下标。不同于上面的是,我们这里不对big进行减操作。在寻找所要求结果的时候,我们是一直操作两个下标。只对他们进行++操作。也就是一直对这两个下标做曾
class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
 		vector<vector<int> >result;
        if(sum < 3){
            return result;
        }
        int small,big,middle,cursum = 0;
        small = 1;//初始化为1
        big = 2;
        middle = (sum+1)/2;//
        cursum = small+big;
        while(small < middle){//每次操作是都要判断是否满足输出要求
            
            if(cursum == sum){//相等的操作对应的是这个
                vector<int> temp;
                gather_result(temp,small,big);
                result.push_back(temp);
            }
            while(cursum > sum && small < middle){//内嵌循环,这个很重要。当太大时对应的操作是这个
                cursum-= small;//并不是每次都对small进行操作,这个是和以往不同的地方。
                small++;//只有++操作
                if(cursum == sum){
                	vector<int> temp;
               	 	gather_result(temp,small,big);
                	result.push_back(temp);
            	}
            }
            big++;//只有++操作,前面两个执行完以后对应的肯定是小于了,所以我们执行crusum增操作。
            cursum+=big;
        }
        return result;//又是忘记了return,导致超时
    }
    void gather_result(vector<int>&result,int small,int big){
        while(small<=big){
            result.push_back(small);
            small++;//少用while,因为自己老是忘记对条件进行自增运算,忘记这个,导致内存不够
        }
    }
};
翻转单词顺序列:
需要考虑的是当句子中没有空格时,还有最后一个单词组。当句子中没有空格时不用进行处理。当是最后一个单词组时,和普通的单词组不一样。
class Solution {
public:
    string ReverseSentence(string str) {
        if(str.size()<1){
            return str;
        }
        bool changed = false;
        int begin = 0;
        int end = 0;
        int length = str.size();
        while(end<length-1){            
            while(begin<length-1&&str[begin]==' '){
                begin++;
            }
            end=begin+1;
            while(end<length-1&&str[end]!=' '){
                end++;
            }
            if(end<length-1&&str[end]==' '){
            	swap_str(str,begin,end-1);
                changed = true;
                begin = end++;                
            }            
        }
        if(end==length-1&&str[begin]!=' '){//最后一个单词组
            if(changed)
                swap_str(str,begin,end);
        }
        if(changed){//如果只有一个单词
            swap_str(str,0,str.size()-1);
        }
        return str;
    }
     void swap_str(string&str,int begin,int end){
        while(begin < end){
            char temp = str[begin];
            str[begin]= str[end];
            str[end]=temp;
            begin++;
            end--;
        }
    }
};

关于链表:我们要考虑这个是否是头结点。头结点的处理和普通节点的处理不一样。还有尾节点。

写递归的时候一定要注意返回条件要先写。

注意处理时我们的循环条件的变动。更新条件变量等关键变量。

注意链表修改可能涉及到头结点,所以我们的参数是二级指针。注意也要修改这个指针。

归并排序不同于其他两种高级排序的地方是:他是一种稳定的排序方法。

归并排序的一种实现:之所以要写出这个代码,主要是因为其少了好多次拷贝。刚开始时,我们让dst和src数据一样,当最后返回时,dst为排好序的数组,src还差一次归并就有序。这里的窍门就是每次递归时都交换data和copy。这样就少了那种传统方法的copy到data的拷贝,但是最终的结果是在copy数组中,所以dst为有序数组。
<pre name="code" class="cpp">void mergesort(int * data,int *copy,int start,int end)
{
     if(start==end){
          copy[start]=data[start];
          return;//注意递归调用的return。
     }
     int length = (end-start)/2;
     mergesort(copy,data,start,start+length);
     mergesort(copy,data,start+length+1,end);


     int i = start+length;
     int j = end;
     int indexCopy = end;
     while(i>=start&&j>=start+length+1){
          if(data[i]>data[j])
               copy[indexCopy--]=data[i--];
          else
               copy[indexCopy--]=data[j--];

     }
     for(;i>=start;--i)
          copy[indexCopy--]=data[i];
     for(;j>=start+length+1;j--)
          copy[indexCopy--]=data[j];
     return ;
}
int main(){
    int src[100];
    int dst[100];
    int i=0;
    while(i<100){
        dst[i]=src[i]= rand()%200;
        cout << src[i]<< "\t";
        i++;
    }
    cout << endl;
    mergesort(src,dst,0,99);
    i=0;
    while(i<100){
        cout << dst[i]<< "\t";
        i++;
    }
    cout << endl;
}
 
if((middleIndex<length-1&&data[middleIndex+1]!=k)||(middleIndex == length-1))

这种在内部对变量做加减操作的一定要先判断是否越界。

判断二叉树是否是平衡的:
先判断子树,再通过子树的结果判断根节点是否平衡。

因为既要判断是否平衡,又要保存子树的深度,所以我们的函数返回值是bool,参数是int&。我们是通过返回值判断读不读传进去的实参的。

注意我们要分别对左右子树调用IsBalanced函数,所以我要定义两个整数,用于左右子树调用。之后如果都满足平衡,我们还要在这个根节点出进行平衡的判断,当两个整数参数的绝对值之差小于等于1时,才满足平衡条件,更新深度为两者最大值加一,并返回true。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值