哈希(3) - 判断一个数组是否为另一个数组的子集

目录

1.简单方法

2.使用排序和二分搜索

3.使用排序和归并

4.使用哈希


给定两个数组:arr1[0..m-1]和arr2[0..n-1],判断arr2[]是否为arr1[]的子集。这两个数组都是无序的。

例如:
输入: arr1[] = {11, 1, 13, 21, 3, 7}, arr2[] = {11, 3, 7, 1}
输出: arr2是arr1的子集。

输入: arr1[] = {1, 2, 3, 4, 5, 6}, arr2[] = {1, 2, 4}
输出: arr2是arr1的子集。

输入: arr1[] = {10, 5, 2, 23, 19}, arr2[] = {19, 5, 3}
输出: arr2不是arr1的子集,因为arr2中的元素3,不存在于arr1中。

1.简单方法

使用两个循环来处理:外层的循环遍历arr2的每个元素。内层的循环逐个的取元素与外层传入的元素进行比较。如果所有元素都匹配成功,则返回1,否则返回0。

#include<iostream>

//如果arr2是arr1的子集,则返回1.
bool isSubset(int arr1[], int arr2[], int numArr1, int numArr2) {
    int i = 0;
    int j = 0;
    for (i = 0; i < numArr2; i++) {
        for (j = 0; j < numArr1; j++) {
            if (arr2[i] == arr1[j])
                break;
        }

        //如果上面的内层循环没有break, 则说明arr2不是arr1的子集
        if (j == numArr1)
            return 0;
    }
    //如果执行到这里,说明arr2是arr1的子集
    return 1;
}

int main() {
    int arr1[] = { 11, 1, 13, 21, 3, 7 };
    int arr2[] = { 11, 3, 7, 1 };

    int numArr1 = sizeof(arr1) / sizeof(arr1[0]);
    int numArr2 = sizeof(arr2) / sizeof(arr2[0]);

    if (isSubset(arr1, arr2, numArr1, numArr2))
        std::cout << "arr2[] is subset of arr1[]";
    else
        std::cout << "arr2[] is not a subset of arr1[]";

    return 0;
}

运行结果:
arr2[] is subset of arr1[]

时间复杂度: O(m*n)

2.使用排序和二分搜索

1) 对arr1[]进行排序, 平均O(mLogm)
2) 对arr2[]中的每个元素,在已排序的arr1[]中进行二分查找。
a) 如果没有找到这个元素,则返回0。
3) 如果所有元素都找到,则返回1。

#include <iostream>

//函数声明 。两个辅助函数,用于判断子集。
void quickSort(int* arr, int si, int ei);
int binarySearch(int arr[], int low, int high, int x);

// 如果arr2[]是arr1[]的一个子集,则返回1
bool isSubset(int arr1[], int arr2[], int numArr1, int numArr2) {
    int i = 0;

    quickSort(arr1, 0, numArr1 - 1);
    for (i = 0; i < numArr2; i++) {
        if (binarySearch(arr1, 0, numArr1 - 1, arr2[i]) == -1)
            return 0;
    }

    //如果执行到了这里,说明arr2是arr1的子集
    return 1;
}

//---------辅助函数begin--------

//标准的二分查找函数
int binarySearch(int arr[], int low, int high, int x) {
    if (high >= low) {
        int mid = (low + high) / 2;  //或者low + (high - low)/2;
        /*
         * 检测arr[mid]是否为第一次遇到x。
         * 当x满足下面情况的一种时,则证明是第一次遇到x:
         (1) (mid == 0) && (arr[mid] == x)
         (2) (arr[mid-1] < x) && (arr[mid] == x)
         */
        if ((mid == 0 || arr[mid - 1] < x) && (arr[mid] == x))
            return mid;
        else if (x > arr[mid])
            return binarySearch(arr, (mid + 1), high, x);
        else
            return binarySearch(arr, low, (mid - 1), x);
    }
    return -1;
}

template<typename type>
void exchange(type* a, type* b) {
    type temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int A[], int si, int ei) {
    int x = A[ei];
    int i = (si - 1);
    int j;

    for (j = si; j <= ei - 1; j++) {
        if (A[j] <= x) {
            i++;
            exchange(&A[i], &A[j]);
        }
    }
    exchange(&A[i + 1], &A[ei]);
    return (i + 1);
}

/*
实现快速排序的函数
A[]:需要排序的数组
si:Starting index
ei:Ending index
*/
void quickSort(int A[], int si, int ei) {
    int pi;    //Partitioning index
    if (si < ei) {
        pi = partition(A, si, ei);
        quickSort(A, si, pi - 1);
        quickSort(A, pi + 1, ei);
    }
}
//---------辅助函数end--------

int main() {
    int arr1[] = { 11, 1, 13, 21, 3, 7 };
    int arr2[] = { 11, 3, 7, 1 };

    int numArr1 = sizeof(arr1) / sizeof(arr1[0]);
    int numArr2 = sizeof(arr2) / sizeof(arr2[0]);

    if (isSubset(arr1, arr2, numArr1, numArr2))
        std::cout << "arr2[] is subset of arr1[]";
    else
        std::cout << "arr2[] is not a subset of arr1[]";

    return 0;
}

运行结果:
arr2[] is subset of arr1[]

时间复杂度: O(mLogm + nLogm)。其中,mLogm是排序算法的平均复杂度。因为上面用的是快速排序,如果是最坏情况,则复杂度会变为O(m^2)。

3.使用排序和归并

1) 对两个数组arr1和arr2分别排序。O(mLogm + nLogn)
2) 使用归并流程来检测已排好序的数组arr2是否存在于排好序的arr1中。参考isSubset函数实现。

#include <iostream>

//函数声明 。两个辅助函数,用于判断子集。
void quickSort(int* arr, int si, int ei);
//如果arr2是arr1的子集,则返回1
bool isSubset(int arr1[], int arr2[], int m, int n) {
    int i = 0, j = 0;

    if (m < n)
        return 0;

    quickSort(arr1, 0, m - 1);
    quickSort(arr2, 0, n - 1);
    while (i < n && j < m) {
        if (arr1[j] < arr2[i])
            j++;
        else if (arr1[j] == arr2[i]) {
            j++;
            i++;
        }
        else if (arr1[j] > arr2[i])
            return 0;
    }

    if (i < n)
        return 0;
    else
        return 1;
}

//---------辅助函数begin--------

//标准的二分查找函数
int binarySearch(int arr[], int low, int high, int x) {
    if (high >= low) {
        int mid = (low + high) / 2;  //或者low + (high - low)/2;
        /*
         * 检测arr[mid]是否为第一次遇到x。
         * 当x满足下面情况的一种时,则证明是第一次遇到x:
         (1) (mid == 0) && (arr[mid] == x)
         (2) (arr[mid-1] < x) && (arr[mid] == x)
         */
        if ((mid == 0 || arr[mid - 1] < x) && (arr[mid] == x))
            return mid;
        else if (x > arr[mid])
            return binarySearch(arr, (mid + 1), high, x);
        else
            return binarySearch(arr, low, (mid - 1), x);
    }
    return -1;
}

template<typename type>
void exchange(type* a, type* b) {
    type temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int A[], int si, int ei) {
    int x = A[ei];
    int i = (si - 1);
    int j;

    for (j = si; j <= ei - 1; j++) {
        if (A[j] <= x) {
            i++;
            exchange(&A[i], &A[j]);
        }
    }
    exchange(&A[i + 1], &A[ei]);
    return (i + 1);
}

/*
实现快速排序的函数
A[]:需要排序的数组
si:Starting index
ei:Ending index
*/
void quickSort(int A[], int si, int ei) {
    int pi;    //Partitioning index
    if (si < ei) {
        pi = partition(A, si, ei);
        quickSort(A, si, pi - 1);
        quickSort(A, pi + 1, ei);
    }
}
//---------辅助函数end--------

int main() {
    int arr1[] = { 11, 1, 13, 21, 3, 7 };
    int arr2[] = { 11, 3, 7, 1 };

    int numArr1 = sizeof(arr1) / sizeof(arr1[0]);
    int numArr2 = sizeof(arr2) / sizeof(arr2[0]);

    if (isSubset(arr1, arr2, numArr1, numArr2))
        std::cout << "arr2[] is subset of arr1[]";
    else
        std::cout << "arr2[] is not a subset of arr1[]";

    return 0;
}

运行结果:
arr2[] is subset of arr1[]

时间复杂度: O(mLogm + nLogn) 。比方法2要好。

4.使用哈希

1) 给数组arr1的所有元素创建一个哈希表。
2) 遍历数组arr2,并检测其中的每个元素是否存在于哈希表中。如果哈希表中没有找到元素,则返回0。
3) 如果所有元素都找到了,则返回1。
注意:方法1,2,4都没有处理arr2数组中有重复元素的情况。例如,{1, 4, 4, 2} 实际上不是 {1, 4, 2}的子集,但上述的这些方法会认为是子集。

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值