Sort the Array

本文探讨了一个关于通过反转数组中某一段来实现整个数组升序排列的问题。文章首先介绍了问题背景及输入输出要求,随后详细解释了算法思路,并提供了一段C++代码实现。通过对数组的遍历和特定条件下的反转操作,判断是否能通过一次反转达到排序目的。

原题链接
B. Sort the Array
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Being a programmer, you like arrays a lot. For your birthday, your friends have given you an array a consisting of n distinct integers.

Unfortunately, the size of a is too small. You want a bigger array! Your friends agree to give you a bigger array, but only if you are able to answer the following question correctly: is it possible to sort the array a (in increasing order) by reversing exactly one segment of a? See definitions of segment and reversing in the notes.

Input
The first line of the input contains an integer n (1 ≤ n ≤ 105) — the size of array a.

The second line contains n distinct space-separated integers: a[1], a[2], …, a[n] (1 ≤ a[i] ≤ 109).

Output
Print “yes” or “no” (without quotes), depending on the answer.

If your answer is “yes”, then also print two space-separated integers denoting start and end (start must not be greater than end) indices of the segment to be reversed. If there are multiple ways of selecting these indices, print any of them.

Examples
input
3
3 2 1
output
yes
1 3
input
4
2 1 3 4
output
yes
1 2
input
4
3 1 2 4
output
no
input
2
1 2
output
yes
1 1
Note
Sample 1. You can reverse the entire array to get [1, 2, 3], which is sorted.

Sample 3. No segment can be reversed such that the array will be sorted.

Definitions

A segment [l, r] of array a is the sequence a[l], a[l + 1], …, a[r].

If you have an array a of size n and you reverse its segment [l, r], the array will become:

a[1], a[2], …, a[l - 2], a[l - 1], a[r], a[r - 1], …, a[l + 1], a[l], a[r + 1], a[r + 2], …, a[n - 1], a[n].

这个题就是把第一个不是上升的区间找出来,将它反转后若是发现还不满足那么他绝对就不可以反转,若是循环结束后没有出现问题那么就说明它是可以的

#include <cstdio>
#include <algorithm>
using namespace std;
int a[100010],f[100010],p=0,q=0;//f[i]是未来的复制数组(a[0]=0,0代表升,1代表降),p是第一个f为1的位置的下标,q是第一个1转0的位置的下标
int main(){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
                scanf("%d",&a[i]);
        a[n]=1000000007;//因为要借助它找到最后一个q
        for(int i=1;i<=n;i++){
                if(a[i]-a[i-1]<0){
                        p=i;
                        for(int j=p+1;j<=n;j++){
                                if(a[j]-a[j-1]>0){
                                        q=j;
                                        goto END;
                                }
                        }
                }
        }
        END:;
        if(p==0 && q==0){//说明此时是完全递增的,不需要修改,那么任取一个值
                printf("yes\n%d %d\n",1,1);
        }
        else{//那么这时pq必然有值,只需要反转a[p-1]到a[q-1]这一段即可
                for(int i=0;i<(p-1);i++) f[i]=a[i];
                for(int i=q-1,t=0;i>=(p-1);i--,t++) f[p-1+t]=a[i];
                for(int i=q;i<n;i++) f[i]=a[i];
                bool flag=true;
                for(int i=1;i<n;i++){
                        if(f[i]-f[i-1]<0){
                                flag=false;
                                break;
                        }
                }
                if(flag){
                        printf("yes\n");
                        printf("%d %d\n",p,q);
                        //for(int i=0;i<n;i++) printf("%d ",f[i]);
                }
                else printf("no\n");
        }
        return 0;
}

### 实现数组排序算法 #### 插入排序 插入排序是一种简单的排序算法,它通过构建有序序列,对于未排序的数据,在已排序序列中从后向前扫描,找到相应位置并插入。 ```c void insertionSort(int arr[], int n) { int i, key, j; for (i = 1; i < n; i++) { key = arr[i]; j = i - 1; while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; j = j - 1; } arr[j + 1] = key; } } ``` #### 希尔排序 希尔排序是对插入排序的一种改进。该方法的基本思想是将整个待排序列分割成若干子序列分别进行直接插入排序,最后再对待排序列进行一次直接插入排序[^1]。 ```c void shellSort(int arr[], int n) { for (int gap = n / 2; gap > 0; gap /= 2) { for (int i = gap; i < n; ++i) { int temp = arr[i]; int j; for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) arr[j] = arr[j - gap]; arr[j] = temp; } } } ``` #### 简单选择排序 简单选择排序的工作原理是每次从未排序部分选出最小(大)的一个元素,存放到序列的起始位置,直到全部待排序的数据元素排完序为止。 ```c void selectionSort(int arr[], int n) { int min_idx; for (int i = 0; i < n-1; i++) { min_idx = i; for (int j = i+1; j < n; j++) if (arr[j] < arr[min_idx]) min_idx = j; swap(&arr[min_idx], &arr[i]); } } // Utility function to swap two elements void swap(int *xp, int *yp) { int temp = *xp; *xp = *yp; *yp = temp; } ``` #### 堆排序 堆排序利用了二叉堆这种数据结构来完成排序操作。首先建立最大堆,然后交换堆顶和最后一个节点的位置,并调整剩余的部分重新成为最大堆,重复此过程直至所有元素都被处理完毕。 ```c void heapify(int arr[], int N, int i) { int largest = i; // Initialize largest as root int l = 2*i + 1; // left = 2*i + 1 int r = 2*i + 2; // right = 2*i + 2 // If left child is larger than root if (l < N && arr[l] > arr[largest]) largest = l; // If right child is larger than largest so far if (r < N && arr[r] > arr[largest]) largest = r; // If largest is not root if (largest != i) { swap(&arr[i], &arr[largest]); // Recursively heapify the affected sub-tree heapify(arr, N, largest); } } void heapSort(int arr[], int N) { // Build max heap for (int i = N / 2 - 1; i >= 0; i--) heapify(arr, N, i); // One by one extract an element from heap for (int i=N-1; i>0; i--) { // Move current root to end swap(&arr[0], &arr[i]); // call max heapify on the reduced heap heapify(arr, i, 0); } } ``` #### 冒泡排序 冒泡排序是一种简单的排序算法,它重复遍历要排序列表,依次比较相邻两个元素大小关系,如果前者大于后者,则两者互换;如此循环往复,最终使得每一轮次的最大值沉底到最右侧。 ```c void bubbleSort(int arr[], int n) { int i, j; bool swapped; for (i = 0; i < n-1; i++) { swapped = false; for (j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { swap(&arr[j], &arr[j+1]); swapped = true; } } // IF no two elements were swapped by inner loop, then break if (!swapped) break; } } ``` #### 快速排序 快速排序采用分治法策略来进行排序。其核心在于选取一个基准元素pivot,按照一定规则把数组分成两半,左边小于等于pivot右边大于等于pivot,递归地对这两边继续执行相同的操作,直到不能再划分下去为止。 ```c int partition (int arr[], int low, int high) { int pivot = arr[high]; int i = (low - 1); for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } ``` #### 归并排序 归并排序也是一种基于分治思想设计出来的高效稳定排序算法。先将原始记录看作n个长度为1的有序区段,之后不断合并这些小区间形成更大的区间,直到只剩下一个完整的升序表为止。 ```c void merge(int arr[], int l, int m, int r) { int i, j, k; int n1 = m - l + 1; int n2 = r - m; /* create temp arrays */ int L[n1], R[n2]; /* Copy data to temp arrays L[] and R[] */ for(i = 0; i < n1; i++) L[i] = arr[l + i]; for(j = 0; j < n2; j++) R[j] = arr[m + 1+ j]; /* Merge the temp arrays back into arr[l..r]*/ i = 0; // Initial index of first subarray j = 0; // Initial index of second subarray k = l; // Initial index of merged subarray while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } /* Copy the remaining elements of L[], if there are any */ while (i < n1) { arr[k] = L[i]; i++; k++; } /* Copy the remaining elements of R[], if there are any */ while (j < n2) { arr[k] = R[j]; j++; k++; } } /* l is for left index and r is right index of the sub-array of arr to be sorted */ void mergeSort(int arr[], int l, int r) { if (l < r) { int m = l+(r-l)/2; mergeSort(arr, l, m); mergeSort(arr, m+1, r); merge(arr, l, m, r); } } ``` #### 基数排序 基数排序是非比较型整数排序算法之一,适用于位数较少的情况。基本思路是从最低有效位开始逐位分配至最高有效位结束,期间借助辅助队列暂存中间结果。 ```c #include<stdio.h> #define d 10 void countSort(int arr[], int n, int exp){ int output[n]; // 输出数组 int i, count[d] = {0}; // 存储出现次数 for (i = 0; i < n; i++) count[(arr[i]/exp)%d]++; // 更改count[i],使其包含实际位置 for (i = 1; i < d; i++) count[i] += count[i - 1]; // 构建输出数组 for (i = n - 1; i >= 0; i--){ output[count[(arr[i]/exp)%d] - 1] = arr[i]; count[(arr[i]/exp)%d]--; } // 将output复制回arr[] for (i = 0; i < n; i++) arr[i] = output[i]; } void radixsort(int arr[], int n){ // 找出最大的数字 int m = getMax(arr, n); // 对每一位做计数排序 for (int exp = 1; m/exp > 0; exp *= 10) countSort(arr, n, exp); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

门豪杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值