Leetcode101 分治法和位运算

158 阅读3分钟

分治法

顾名思义,分治问题由“分”(divide)和“治”(conquer)两部分组成,通过把原问题分为子问题,再将子问题进行处理合并,从而实现对原问题的求解。我们在排序章节展示的归并排序就是典型的分治问题,其中“分”即为把大数组平均分成两个小数组,通过递归实现,最终我们会得到多个长度为 1 的子数组;“治”即为把已经排好序的两个小数组合成为一个排好序的大数组,从长度为 1 的子数组开始,最终合成一个大数组。

(1)241. Different Ways to Add Parentheses (Medium)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述

给定一个只包含加、减和乘法的数学表达式,求通过加括号可以得到多少种不同的结果。

个人思路

利用分治思想,我们可以把加括号转化为,对于每个运算符号,先执行处理两侧的数学表达式,再处理此运算符号。注意边界情况,即字符串内无运算符号,只有数字。

代码展示

vector<int> diffWaysToCompute(string expression) {
    vector<int> ans;
    vector<int> left;
    vector<int> right;
    for(int i=0;i<expression.length();i++){
        char c=expression[i];
        if(c=='+'||c=='-'||c=='*'){
            left=diffWaysToCompute(expression.substr(0,i));
            right=diffWaysToCompute(expression.substr(i+1));
            for(const int& l:left){
                for(const int& r:right){
                    int result;
                    switch(c){
                        case '+': result = l + r; break;
                        case '-': result = l - r; break;
                        case '*': result = l * r; break;
                    }
                    ans.push_back(result);
                }
            }
        }
    }
    if(ans.empty()){ // 处理表达式是纯数字的情况
        ans.push_back(stoi(expression));
    }
    return ans;
}

位运算

位运算是算法题里比较特殊的一种类型,它们利用二进制位运算的特性进行一些奇妙的优化和计算。常用的位运算符号包括:“∧”按位异或、“&”按位与、“|”按位或、“∼”取反、“<<”算术左移和“>>”算术右移。

(1)461. Hamming Distance (Easy)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述

给定两个十进制数字,求它们二进制表示的汉明距离(Hamming distance,即不同位的个数)。

个人思路

没啥好说的,对两个数进行按位异或操作,统计有多少个 1 即可。

代码展示

int hammingDistance(int x, int y) {
		int diff = x ^ y, ans = 0;
				while (diff) {
						ans += diff & 1;
						diff >>= 1;
				}
				return ans;
}

(2)190. Reverse Bits (Easy)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述

给定一个32位十进制整数,输出它在二进制下的翻转结果。

个人思路

这个和第一题的思路是一样的,都比较简单,唯一需要注意的一点就是必须要把32位遍历完(0也得补上),不然会error。

代码展示

uint32_t reverseBits(uint32_t n) {
    uint32_t ans=0;
    int k=32;
    while(k>0){
        ans<<=1;
        ans+=n&1;
        n>>=1;
        k--;
    }
    return ans;
}

(3)136.Single Number (Easy)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述

给定一个整数数组,这个数组里只有一个数次出现了一次,其余数字出现了两次,求这个只出现一次的数字。

个人思路

以前在算法课上老师提到过这点。方法很巧妙,就是利用异或来计算就行。出现两次的所有数字按位异或的结果是 0,0 与出现一次的数字异或可以得到这个数字本身。

代码展示

int singleNumber(vector<int>& nums) {
    int ans=0;
    for(const int& num:nums){
        ans=ans^num;
    }
    return ans;
}

总结

分治法将问题分解成子问题,递归地解决后合并,适用于具有相似结构的大问题。位运算是对二进制数的操作,如与、或、异或等,用于解决特定问题,如查找单独元素、交换值等。分治法解决大问题,位运算处理二进制操作。