堆排序,用一种清新脱俗的方式

最近用OC写算法时遇到这么一道题:

问题:给定一个字符数组,判断字符数组中是否所有的字符只出现过一次,如果是,那么返回yes,否则返回no。

第一种解法很简单,我们通过开辟空间创建Hash表比较即可,代码如下:

BOOL detectString(char *str){
    NSUInteger len = strlen(str);
    int hash[256] = {0};
    for (int i =0; i<len; i++) {
        if (hash[str[i]] != 0) {
            return NO;
        } else {
            hash[str[i]]++;
        }
    }
    return YES;
}

代码是最基本的C语言代码。可能有些小白会问为什么要开辟256大小的空间呢?这个可以查看下ASCII码中字符的编码即可明白。

当然,以上这种方法不是我要记录的内容,当把这道题进行延伸,说在空间复杂度为O(1)的情况下,如何能够使得时间复杂度最小呢?(也就是不去开辟空间)。要想比较,那么只能通过将字符数组进行排序,比较相邻的字符是否相同来解决。这样就把问题转化道了排序算法上,选取一个空间复杂度为O(1),时间复杂度最低的算法,那就是本文的主角堆排序算法。下面就把这种清新脱俗的堆排序算法贴上来,代码如下:

/**
 建立一个堆

 @param str 传入的字符串数组
 @param i 插入到第几个位置
 */
void heapInsert(char *str,NSUInteger i);
//交换两个值
void swap(char *str,NSUInteger i,NSUInteger j);
void heapify(char *str,NSUInteger i, NSUInteger size);   //排序调整
//方法二
BOOL detectString2(char *str){
    NSUInteger len = strlen(str);
    char newStr[len];
    strcpy(newStr, str);
    //建立堆
    for (NSUInteger i=0; i<len; i++) {
        heapInsert(newStr, i);
    }
//    排序调整
    for (NSUInteger i = len-1; i>0; i--) {
        swap(newStr, 0, i);
        heapify(newStr, 0, i);
    }
    //判断是否有重复字符出现
    for (NSUInteger i = 1; i<len; i++) {
        if (newStr[i] == newStr [i-1]) {
            return NO;
        }
    }
    return YES;
}
//建立堆
void heapInsert(char *str,NSUInteger i) {
    NSUInteger parent = 0;
    while (i != 0) {
        parent = (i-1)/2;
        if (str[parent] < str[i]) {
            swap(str, parent, i);
            i = parent;
        } else {
            break;
        }
    }
}
//交换节点
void swap(char *str,NSUInteger i,NSUInteger j) {
    char temp = str[i];
    str[i] = str[j];
    str[j] = temp;
}
堆排序
void heapify(char *str,NSUInteger i, NSUInteger size) {
    NSUInteger left = i*2+1;
    NSUInteger right = i*2+2;
    NSUInteger largest = i;
    while (left < size) {
        if (str[left] > str[i]) {
            largest = left;
        }
        if (right < size && str[right] > str[left]) {
            largest = right;
        }
        if (largest != i) {
            swap(str, i, largest);
        } else {
            break;
        }
        i = largest;
        left = i*2+1;
        right = i*2+2;
    }
    
}

点赞