微软面试题解

本文深入解析了多种经典算法问题,包括子集生成、随机洗牌、最长不重复子串、括号匹配验证、升序数列查找、股票买卖策略、0-1背包问题、对称树判断等,提供高效解决方案及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.如果有64个元素(不重复),那么有多少子集? 全部打印且不能占用额外的内存空间。
做法:有2^64种情况。不能占用额外空间的话,深搜和广搜都不可以,一个调用栈和使用队列都需要额外的内存空间。因此可以考虑二进制的做法,64位刚好是long int。

class Solution {
public:
	void permunation(vector<int> nums) {
		int n = nums.size();
		vector<vector<int>> res;
		for (long i = 0; i < (1<<n); i++) { //1<<n,将1左移n位,就是2^n
			vector<int> tmp;
			for (int j = 0; j < n; j++) {
				if ((i & (1 << j))!= 0) //注意要加两层括号,!=的优先级高于&
					tmp.push_back( nums[j]); //1向左移j位
			}
			res.push_back(tmp);
		}
	}
};

2.随机洗牌程序,空间复杂度O(1)。

class Solution {
public:
	void shuffle(vector<int> nums) {
		int n = nums.size();
		srand((int)time(0));
		for (int i = n - 1; i >= 0;i--) {
			int j = rand() % (i + 1);
			swap(nums[i], nums[j]); 
		}	
	}
};

3.最长不重复子串
这个题可以这样思考:ABCDBACEF这样的字符串,当我们知道位置5和位置2的B重复之后,得到了ABCD这样一个最长串,那么在位置5的B之前不会有更长的字符串了,要找只能从上一个重复的B(即位置2的B)之后开始找新的串。
使用两个指针left和right,记录最长串的左右两端,形成一个有效坐标的区间(使用这种方法是避免重置左端的时候还要擦除map中的记录)。如果新找的字符在map中有记录且它最近出现的一次也在有效区间,说明重复了。

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		if (s.length() <= 1) return s.length();
        //记录字符和其最后一次出现的位置
		unordered_map<char, int> record;
		int left = 0;
		int right = 1;
		int res = 0;
		record.insert(make_pair(s[left], left));
		while (right<s.length()) {
            //如果字符之前出现过且在有效区间内,说明重复了
			if (record.find(s[right]) != record.end() && record[s[right]] >= left) {
				res = max(res, right - left);
				left = record[s[right]] + 1;
				record[s[right]] = right;
			}
			else {
                //如果字符之前出现过但没在有效区间,则不影响,已经是无用位置了。但需要更新一下最新位置。
				if (record.find(s[right]) != record.end()) record[s[right]] = right;
                //直接没出现过,记下来。
				else record.insert(make_pair(s[right], right));
			}
			right++;
		}
        return max(res,right-left); //处理最长不重复子串在最后一段的情况
	}
};

4.有()[]{}三种括号组成的序列,判断序列内的括号是否全部匹配

class Solution {
public:
    bool isValidParentheses(string &s) {
        stack<char> res;
        for (int i=0;i<s.length();i++)
        {
            if (s[i]=='('||s[i]=='['||s[i]=='{') res.push(s[i]);
            else 
            {
                if (res.empty()) return false; //有右括号没有左括号的情况
                char tmp=res.top();
                res.pop();
                if (s[i]==')'&&tmp!='(') return false; //匹配不正确的情况
                if (s[i]==']'&&tmp!='[') return false;
                if (s[i]=='}'&&tmp!='{') return false;
            }
        }
        if (!res.empty()) return false;//有左括号多余的情况
        return true;
    }
};

5.follow up求出最长的有效括号序列
题目类似longest-valid-parentheses,这个题是只考虑一种括号的情况,可以用栈和动态规划两种算法

class Solution {
public:
    int longestValidParentheses(string s) {
        if (s.length()<=1) return 0;
        
        stack<int> left_index;
        int start=0;
        int res=0;
        for (int i=0;i<s.length();i++) {
            if (s[i]=='(') {
                left_index.push(i);
                continue;
            } else if (left_index.empty()) {start=i+1; continue;} //形不成更长的有效括号序列了,重置start找新的
                   else {
                       left_index.pop();
                       if (left_index.empty()) res=max(res,i-start+1);//找到最长的 如 (()(()))从头到尾
                       else res=max(res,i-left_index.top());//找到局部最长的,如(()(())) 第2,3个括号是局部最长
                   }
        }
        return res;
    }
};
class Solution {
public:
	int longestValidParentheses(string s) {
		if (s.length() <= 1) return 0;
		int res = 0;
		vector<int> dp(s.length(), 0);
		for (int i = s.length() - 2; i >= 0; i--) {
			if (s[i] == '(' && s[i+1 + dp[i+1]] == ')') {
				dp[i] = dp[i+1] + 2; //扩展局部最长有序括号
				if (i+1 + dp[i+1] + 1<s.length() && dp[i+1+dp[i+1]+1]>0) 
                    dp[i] = dp[i] + dp[i+1 + dp[i+1] + 1];//连接后面有可能出现的其他括号
			}
			res = max(res, dp[i]);
		}
		return res;
	}
};

只要多加一个判断括号种类是否一致即可。

6.升序数列找target
34. Find First and Last Position of Element in Sorted Array
一定要问清楚要求,比如特殊情况如何返回等!!!

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if (nums.size()<=0) return vector<int>(2,-1);
        
        int i=0;
        int j=nums.size()-1;
        while (i+1<j) {
            int mid=(j-i)/2+i;
            if (nums[mid]>=target) j=mid;
            else i=mid+1;
        }
        vector<int> res;
        if (nums[i]!=target && nums[j]==target) i=j;
        if (nums[i]==target ) {
            res.push_back(i);
            int tmp=i;
            while (i+1<nums.size() && nums[i+1]==target) i++;
            res.push_back(i);
        }else 
        {
            res.push_back(-1);
            res.push_back(-1);
        }
        return res;
    }
};

7.股票买卖问题
https://blog.youkuaiyun.com/musechipin/article/details/88841590

8.0-1背包
​​​​​​​https://blog.youkuaiyun.com/musechipin/article/details/88623481

9.判断一个数是否为对称树
https://blog.youkuaiyun.com/musechipin/article/details/85005947

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值