Cranking the Coding Interview: Sorting and Searching

No buffer interchange

函数内不使用任何临时变量,直接交换两个数的值。

给定一个int数组AB,其第零个元素和第一个元素为待交换的值,请返回交换后的数组。

class Exchange {
public:
    vector<int> exchangeAB(vector<int> AB) {
        AB[0] = AB[1] - AB[0];
        AB[1] = AB[1] - AB[0];
        AB[0] = AB[0] + AB[1];
        return AB;
    }
};

Group angrams

对一个字符串数组进行排序,将所有变位词合并,保留其字典序最小的一个串。这里的变位词指变换其字母顺序所构成的新的词或短语。例如”triangle”和”integral”就是变位词。

给定一个string的数组str和数组大小int n,请返回排序合并后的数组。保证字符串串长小于等于20,数组大小小于等于300。

在这道题目中有两个需求,一个是去重保留顺序更前面的字符串,第二个是对不重复的字符串进行排序。

代码实现:

class SortString {
public:
    __inline void calculateHash(vector<int>& hash, string str) {
        for(int i = 0, sz = str.length(); i < sz; i++)
            hash[str[i]-'a']++;
    }

    __inline void mergeSort(vector<string>& res, vector<string>& helper, int low, int high) {
        if(low < high) {
            int mid = (low + high) >> 1;
            mergeSort(res, helper, low, mid);
            mergeSort(res, helper, mid+1, high);
            mergeArray(res, helper, low, mid, high);
        }
    }

    void mergeArray(vector<string>& arr1, vector<string>& arr2, int low, int mid, int high) {
        for(int i = low; i <= high; i++) arr2[i] = arr1[i];
        int helperLeft = low, helperRight = mid+1, cur = low;
        while(helperLeft <= mid && helperRight <= high) {
            if(arr2[helperLeft] <= arr2[helperRight]) {
                arr1[cur] = arr2[helperLeft];
                helperLeft++;
            }
            else {
                arr1[cur] = arr2[helperRight];
                helperRight++;
            }
            cur++;
        }
        int rem = mid - helperLeft;
        for(int i = 0; i <= rem; i++) arr1[cur+i] = arr2[helperLeft + i];
    }

    vector<string> sortStrings(vector<string> str, int n) {
        vector<string> res;
        vector<vector<int>> hash_table(300, vector<int>(26, 0));
        if(!n) return res;
        res.push_back(str[0]);
        calculateHash(hash_table[0], str[0]);
        for(int i = 1; i < n; i++) {
            vector<int> hash_cur(26, 0);
            calculateHash(hash_cur, str[i]);
            for(int j = 0, cur_size = res.size(); j < cur_size; j++) {
                if(hash_cur == hash_table[j]) {
                    if(str[i] < res[j]) res[j] = str[i];
                }
                else if(j == cur_size - 1){
                    res.push_back(str[i]);
                    hash_table[cur_size] = hash_cur;
                }
            }    
        }

        vector<string> helper(res.size(), "");
        mergeSort(res, helper, 0, res.size() - 1);

        return res;
    }
};

一个稀疏矩阵需要进行二分查找,需要注意字符串为空的情况。

有一个排过序的字符串数组,但是其中有插入了一些空字符串,请设计一个算法,找出给定字符串的位置。算法的查找部分的复杂度应该为log级别。

给定一个string数组str,同时给定数组大小n和需要查找的string x,请返回该串的位置(位置从零开始)。

代码实现:

class Finder {
public:
    int findString(vector<string> str, int n, string x) {
        int low = 0, high = n - 1;
        while(low <= high) {
            while(str[low].empty()) low++;
            while(str[high].empty()) high--;
            int mid = (low + high) >> 1;
            int leftBnd = mid, rightBnd = mid;
            while(leftBnd >= low && str[leftBnd].empty()) leftBnd--;
            while(rightBnd <= high && str[rightBnd].empty()) rightBnd++;
            if(str[leftBnd] == x || str[rightBnd] == x) return leftBnd;
            else if(str[rightBnd] < x) low = rightBnd + 1;
            else if(str[leftBnd] > x) high = leftBnd - 1;
        }
        return -1;
    }
};

Search in Rotated Array

有一个排过序的数组,包含n个整数,但是这个数组向左进行了一定长度的移位,例如,原数组为[1,2,3,4,5,6],向左移位5个位置即变成了[6,1,2,3,4,5],现在对于移位后的数组,需要查找某个元素的位置。请设计一个复杂度为log级别的算法完成这个任务。

给定一个int数组A,为移位后的数组,同时给定数组大小n和需要查找的元素的值x,请返回x的位置(位置从零开始)。保证数组中元素互异。

就是将一个数组进行旋转,然后找到需要找到的数字的索引,然后返回。

这里需要注意的就是索引的使用会有些复杂。

这里我实现的思路是先找到最小元素的索引,在这个基础上,在进行二分查找。

代码实现:

class Finder {
public:
    int findElement(vector<int> A, int n, int x) {
        int low = 0, high = n - 1, mid = 0;
        while (low <= high) {
            mid = (low + high) >> 1;
            if (A[mid] > A[low]) low = mid;
            else if (A[mid] < A[high]) high = mid;
            else {
                if (A[high] < A[low]) { mid = high; break; }
                else { mid = low; break; }
            }
        }
        low = mid, high = mid ? mid - 1 : n - 1;
        int abt_low = 0, abt_high = n - 1;
        while (abt_low <= abt_high) {
            int abt_mid = (abt_low + abt_high) >> 1;
            mid = (abt_mid + low) % n;
            if (A[mid] > x)  abt_high = abt_mid - 1;
            else if (A[mid] < x)  abt_low = abt_mid + 1;
            else return mid;
            if (A[(abt_low + low) % n] == x) return (abt_low + low) % n;
            if (A[(abt_high + low) % n] == x) return (abt_high + low) % n;
        }
        return -1;
    }
};

word frequency

请设计一个高效的方法,找出任意指定单词在一篇文章中的出现频数。

给定一个string数组article和数组大小n及一个待统计单词word.

代码实现:

class Frequency {
public:
    __inline bool isEqual(string a, string b) {
        int lena = a.size(), lenb = b.size();
        if(lena != lenb) return false;
        for(int i = 0; i < lena; i++) if(a[i] ^ b[i])  return false;
        return true;
    }

    int getFrequency(vector<string> article, int n, string word) {
        int res = 0;
        for(int i = 0; i < n; i++) {
            res += isEqual(word, article[i]);
        }
        return res;
    }
};

no if max implementation

请编写一个方法,找出两个数字中最大的那个。条件是不得使用if-else等比较和判断运算符。

给定两个int a和b,请返回较大的一个数。若两数相同则返回任意一个。

这道题目里,不能使用if else这样的结构,那么就需要进行一些逻辑判断,使用逻辑运算来代替if else的结构。

代码实现:

class Max {
public:
    int getMax(int a, int b) {
        int bs = ((a - b) >> 31) & 1;
        int as = 1 - bs;
        for(int i = 1; i < 32; i++) {
            bs = bs | (bs << i);
            as = as | (as << i);
        }
        return (bs & b) | (as & a);
    }
};

chess board

对于一个给定的井字棋棋盘,请设计一个高效算法判断当前玩家是否获胜。

给定一个二维数组board,代表当前棋盘,其中元素为1的代表是当前玩家的棋子,为0表示没有棋子,为-1代表是对方玩家的棋子。

判断一个棋盘中当前玩家是否赢了。

既然这道题目的棋盘大小是固定的,那么就可以直接判断。

代码实现:

class Board {
public:
    bool checkWon(vector<vector<int> > board) {
        for(int row = 0; row < 3; row++) {
            for(int col = 0; col < 3; col++) {
                if(board[row][col] == 1) {
                    if(col == 0) {
                        // 1
                        if(board[row][1] == 1 &&  board[row][2] == 1) return true;
                        // 2
                        if(row == 0) {
                            if(board[1][1] == 1 && board[2][2] == 1) return true;
                        }
                    }
                    // 3
                    if(row == 0) {
                        if(board[1][col] == 1 && board[2][col] == 1) return true;
                        // 4
                        if(col == 2) {
                            if(board[1][1] == 1 && board[2][0] == 1) return true;
                        }
                    }
                }
            }
        }

        return false;
    }
};

guess score

我们现在有四个槽,每个槽放一个球,颜色可能是红色(R)、黄色(Y)、绿色(G)或蓝色(B)。例如,可能的情况为RGGB(槽1为红色,槽2、3为绿色,槽4为蓝色),作为玩家,你需要试图猜出颜色的组合。比如,你可能猜YRGB。要是你猜对了某个槽的颜色,则算一次“猜中”。要是只是猜对了颜色但槽位猜错了,则算一次“伪猜中”。注意,“猜中”不能算入“伪猜中”。

给定两个string A和guess。分别表示颜色组合,和一个猜测。请返回一个int数组,第一个元素为猜中的次数,第二个元素为伪猜中的次数。

这道题目比较简单,其实只需要把字符创中相等的部分进行计算得到第一个返回的数据。然后第二个返回的数据就排除第一次比较相等的数据,然后使用一个哈希表记录即可得到正确的结果。

class Result {
public:
    vector<int> calcResult(string A, string B) {
        int hash[4] = {0}; // 1, 2, 3, 4
        int rgb[4] = {0};
        vector<int> res(2, 0);
        for(int i = 0; i < 4; i++) {
            if(A[i] ^ B[i]) hash[i] = INT_MAX; 
            else res[0]++;
        }
        for(int i = 0; i < 4; i++) {
            if(hash[i] == INT_MAX) {
                switch(A[i]) {
                    case 'R': {
                        if(rgb[0] < 0) res[1]++; rgb[0]++;    
                        break;
                    }
                    case 'G': {
                        if(rgb[1] < 0) res[1]++; rgb[1]++;
                        break;
                    }
                    case 'Y': {
                        if(rgb[2] < 0) res[1]++; rgb[2]++;
                        break;
                    }    
                    default: {
                        if(rgb[3] < 0) res[1]++; rgb[3]++;
                    }
                }
                switch(B[i]) {
                    case 'R': {
                        if(rgb[0] > 0) res[1]++; rgb[0]--; break;    
                    }
                    case 'G': {
                        if(rgb[1] > 0) res[1]++; rgb[1]--;
                        break;
                    }  
                    case 'Y': {
                        if(rgb[2] > 0) res[1]++; rgb[2]--;
                        break;
                    }      
                    default: {
                        if(rgb[3] > 0) res[1]++; rgb[3]--;
                    }    
                }
            } 
        }

        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值