1道排序(快排)1道动态规划(最大连续子序列)1道递归(汉诺塔)1道杂题(输出菱形)

**

1.输入n个数,奇数在前,偶数在后,分别由小到大排序。

**
例如输入:[8,4,2,1],输出[1,2,4,8]。
输入:[1,2,3,4,5,6,7,8],输出[1,3,5,7,2,4,6,8]
思路:
1.先把奇数放到头部,偶数沉到尾部。
2.分别对奇序列和偶序列进行快排。
相关知识点:快排,双指针
快排是对冒泡排序的一种改进。每次快速排序选中一个privot基准数,将比privot小的数放到privot左边,大的放到右边。对一个数组进行快速排序,一共要进行logn次这样的操作。时间复杂度为O(nlogn)。
手写快排:

void quickSort(int left,int right,int* (&array)){
    int recordLeft = left;     //保存初始left指针
    int recordRight = right;   //保存初始right指针
    bool isLeftPoint = false;   //初始指针从右开始
    if(left<right){
        int privot = array[left];   //每次选取的基准数
        while(true){
            if(left == right){
                array[left] = privot;  //left=right,一次快排结束。
                break;
            }else{
                if(!isLeftPoint){  //指针在右面
                    if(array[right]<privot){
                        array[left] = array[right];
                        left += 1;
                        isLeftPoint = true;
                    }else{
                        right -= 1;
                    }
                }else{
                    if(array[left]>privot){
                        array[right] = array[left];
                        right -= 1;
                        isLeftPoint = false;
                    }else{
                        left += 1;
                    }
                }
            }
        }
        quickSort(recordLeft,left-1,array); //递归对privot左进行快排
        quickSort(left+1,recordRight,array);//递归对privot右进行快排
    }
}

区分奇偶的操作我们也可以借鉴这个双指针的思想。左指针指向首元素,右指针指向尾元素,最后返回最后一个奇数的下标。
具体来说,分四种情况。
1.如果左指针指向的数是奇数,右指针指向的数是偶数,左指针后移,右指针前移。
2.如果左指针指向的数是偶数,右指针指向的数是奇数,交换左右指针的数,左指针后移,右指针前移。
3.如果左右指针指向的数都是奇数,左指针后移。
4.如果左右指针指向的数均是偶数,右指针前移。
如果左指针大于右指针,break。

int jiOu(int left,int right,int* (&array)){
    int tmp;
    while(true){
        if(left>right){
            break;
        }else{
            if((array[left]%2 == 1)&&(array[right]%2 ==0)){
                left += 1;
                right -= 1;
            }else if((array[left]%2 == 0)&&(array[right]%2 ==1)){
                tmp = array[left];
                array[left] = array[right];
                array[right] = tmp;
                left += 1;
                right -= 1;
            }else if((array[left]%2 == 1)&&(array[right]%2 ==1)){
                left += 1;
            }else{
                right -= 1;
            }
        }
    }
    return right;
}

主函数

int main(){
    int num;
    cin>>num;   //输入几个数
    int array[num];
    int input;
    for(int i=0;i<num;i++){
        cin>>input;
        array[i] = input;
    }
    int* arrayPoint = array;
    int jiBoard = jiOu(0,num-1,arrayPoint);  //划分奇偶序列
    quickSort(0,jiBoard,arrayPoint);//奇数快排
    quickSort(jiBoard+1,num-1,arrayPoint);//偶数快排
    for(int i=0;i<num;i++){ //打印结果。
        cout<<array[i]<<" ";
    }
    return 0;
}

**

2.最大连续子序列

**
输入一个数组array,输出其最大连续子序列的和。
如array = [-2 11 -4 13 -5 -2]输出20。11 -4 13为最大子序列。
思路:
定义sum(i,j)表示从i到j的子序列的和。
定义一个长度为n的一维数组record,其中第k个元素记录max{sum(1,k),sum(2,k)…sum(k,k)}。
则有:
record[n] = array[0] (n = 0)
record[n] = max{record[n-1]+array[n],array[n]}

则最长子序列的和就是:
max{record[1],record[2],…record[n]}

#include <iostream>
using namespace std;
int maxNum(int num1,int num2);
int main(){
	int arrayNum;  //输入要输入数的个数
	cin>>arrayNum; 
    int* array = (int *) malloc(sizeof(int) * arrayNum);
	for(int i=0;i<arrayNum;i++){
		int num;
		cin>>num;
		array[i] = num;  //输入要求解的数组array
	}

    int sum = 0;
    int* record = (int*) malloc(sizeof(int)*arrayNum);
    record[0] = array[0];
    int result = record[0];  //最大连续子序列结果
    for(int i=1;i<=arrayNum-1;i++){
        record[i] = maxNum(record[i-1]+array[i],array[i]);  //计算record
        if(result<record[i]){
            result = record[i];  //找到更大得最长子序列,更新结果。
        }
    } 
    cout<<result;
	return 0;
}
int maxNum(int num1,int num2){
	/*
		返回num1和num2中的最大值
	*/
    return (num1>=num2)?num1:num2;
}

3.汉诺塔

A柱上有n个盘,怎么原封不动移到C柱上,大盘不能压小盘。5个一行,打印移动序列。
例如输入2:就打印:
A–>B A–>C B–>C
输入1:就打印:
A–>C
输入0退出。

思路:考虑子问题。
n = 1
A–>C

n = 2
A–>B 将2-1(n-1)个盘从A–>B
A–>C
B–>C 将2-1(n-1)个盘从B–>C

n = 3
A–>C 将3-1(n-1)个盘从A–>B
A–>B
C–>B
A–>C
B–>A 将3-1(n-1)个盘从B–>C
B–>C
A–>C
通过观察我们发现,将n个盘从A–>C由三部分组成:
1.将n-1个盘从A–>B(中转柱)
2.将1个盘(A最底下那个盘)从A–>C
3.将n-1个盘从B(中转柱)–>C
这里的B是一个中转柱。比如某任务要求把k个盘从柱A运到柱C,B就是中转柱。
写一个求中转柱的函数。

char getFree(int a,int b){
    if(a=='A'){
        if(b == 'B'){
            return 'C';
        }else if(b == 'C') {
            return 'B';
        }
    }else if(a =='B'){
        if(b =='A'){
            return 'C';
        }else if(b == 'C'){
            return 'A';
        }
    }else{
        if(b =='A'){
            return 'B';
        }else if(b == 'B'){
            return 'A';
        }
    }
}

有了以上的递归思想,就可以编写出把num个盘从start柱移动到end柱的函数。

void sOutStep(char start,char end,int num){
	/*
		count用于计数,5个一换行
	*/
    if(num == 1){
        if((count%5==0)&&(count!=0)){
            cout<<endl;
        }
        cout<<start<<"-->"<<end<<"   ";
        count++;
    }else{
        char free = getFree(start,end);  //中转柱
        
        //第一步:递归
        sOutStep(start,free,num-1);
        
        //第二部:A-->C
        if((count%5==0)&&(count!=0)){
            cout<<endl;
        }
        cout<<start<<"-->"<<end<<"   ";
        count++;

		//第三步:递归
        sOutStep(free,end,num-1);
    }
}

最后主函数如下:

int count = 0;   //用于换行计数,全局变量。
int main(){
    bool loop = true;
    int num;
    while(loop){
        cin>>num;
        switch(num){
            case 0:   //输入0,退出程序。
                loop = false;
                break;
            default:   //否则,打印把n个盘从'A'移动到'C'的序列。
                count = 0;
                sOutStep('A','C',num);
                cout<<endl;
                break;
        }
    }

	return 0;
}

**

4.输出菱形

**
输入一个整数n,控制台输出对应的菱形,例如:

n = 1;
输出:
在这里插入图片描述

n = 3;
输出
在这里插入图片描述
思路:找规律,每一行先输出若干空格,再输入若干个*。

#include<iostream>
using namespace std;
void printlonzenge(int num);
int main(){
    int num;
    cin>>num;
    printlonzenge(num);
    return 0;
}
void printlonzenge(int num){
    for(int i = 1;i<2*num;i++){
        for(int j = 0;j<((num-i>0)?(num-i):(-num+i));j++){
            cout<<' ';
        }  //输出若干个空格
        for(int k = 0;k<((i<=num)?2*i-1:4*num-2*i-1);k++){
            cout<<'*';
        }  //输出若干个*
        cout<<endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值