校招算法笔面试 | 校招笔面试真题-扎金花

题目## 题目## 题目## 题目

题目链接

#题解
##题目难度:中等难度
###难点分析:
1.对于四个数字具有24种排列方式。比如:1 2 3 4 可以重新排列为1 3 4 2、4 3 2 1等情况。

2.两个数字之间可以插入任意符号“+” 、“-”、“*”、“/”,四个数字一共有3个符号

3.运算符具有优先级,需要先进行“*”、“/”运算,再进行“+”、“-”运算。

##知识点:栈、全排列、字典序、四则运算

#思路:
##首先思考一个运算式子的计算过程:(使用栈)
如 1 + 3 * 5 - 6

其中数字放入数组a种,运算符放入数组b种(1表示“+”,2表示“-”,3表示“*”,4表示“/”)

####数组a:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

####数组b:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

##第一步:
将a[0]压入栈s中
##第二步:
依次判断每个运算符:

如果是“+”和“-”,直接压入栈s中(不能直接运算,需要继续判断之后是否存在“*”“/”优先级更高的运算符)。

如果是“*”、“/”,弹出栈顶元素进行乘或者除操作。

##第三步:
在第二步中,所用的乘除运算已经运算完成,现在进行加减运算。由于栈先弹出后压入的数字,同时加减运算满足结合

律,因此对数组b运算符逆序依次判断:

###当b[x]=1时:
弹出栈顶两个元素,将相加之和压入栈中

###当b[x]=2时:
弹出栈顶两个元素相减,注意:后后弹出元素减先弹出元素

####当b[x]=3或者b[x]=4时:
由于第二步已经运算过,直接跳过(代码中,在第二步乘除运算后将b[x]赋值为0,因此当b[x]=0时直接跳过运算即可)。

##第四步:
通过第三步运算,栈中比保存一个元素,即为运算结果。

##考虑数组a中数组的顺序问题,使用STL对其进行全排列。
STL中有两个关于全排列的函数,分别为next_permutation(下一个排列)和prev_permutation(上一个排列),这两

个算法都是以“字典序”为准则进行全排列的。所谓某一序列的全排列,指的是:“序列上每一位都取完该序列所包含的所

有元素”,如“123”的全排列为:“123”、“132”、“213”、“231”、“312”、“321”,共6种情况。

####【注】得到通过next_permutation(下一个排列)函数得到全排列需要先对数字进行排序

##关于运算符数组b:
通过三层for循环得到,每层循环代表一个位置的符号,包括四种情况(1表示“+”,2表示“-”,3表示“*”,4表示“/”)

#include<iostream>
#include<stack>
#include<algorithm>
using namespace std;
int main(){
	int n=4,m;
	stack<int> s;
	int a[n];
	for(int i=0;i<n;i++){ cin>&gt;a[i];
	}
	cin&gt;&gt;m;
	sort(a,a+4); 
    do{
	for(int i=1;i&lt;=4;i++){
		for(int j=1;j&lt;=4;j++){
			for(int k=1;k&lt;=4;k++){
				s.push(a[0]);
				int b[3];
				b[0]=i;b[1]=j;b[2]=k;		
				for(int x=0;x&lt;3;x++){
					if(b[x]==1||b[x]==2) s.push(a[x+1]);
				    else{
					    int tmp=s.top();
					    s.pop();
					    if(b[x]==3) s.push(tmp*a[x+1]);
					    else s.push(tmp/a[x+1]); 
					    b[x]=0;
				    }
			    }
			    for(int x=2;x&gt;=0;x--){
			    	if(b[x]==0) continue;
			    	else if(b[x]==1) {
			    		int tmp;
			    		tmp=s.top();
			    		s.pop();
			    		tmp+=s.top();
			    		s.pop();
			    		s.push(tmp);
					}else{
						int tmp;
			    		tmp=s.top();
			    		s.pop();
			    		tmp=s.top()-tmp;
			    		s.pop();
			    		s.push(tmp);
					}
				}
	  //  cout&lt;</n;i++){></int></algorithm></stack></iostream>

[题目链接](https://www.nowcoder.com/practice/f4e2fc37f9a54787a7c2846873e8b827?tpId=182&tqId=36485&sourceUrl=/exam/oj&channelPut=wcsdn&fromPut=wcsdn)

## 解题思路

1. 牌型规则(从大到小):
   - 豹子:三张相同的牌
   - 顺子:三张连续的牌
   - 对子:两张相同的牌
   - 普通牌:比较最大牌

2. 解题步骤:
   - 解析输入字符串,转换为数字(2-14,其中J=11,Q=12,K=13,A=14)
   - 对每个玩家的牌排序
   - 判断牌型
   - 按规则比较大小

---

## 代码

```cpp []
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 将字符串转换为牌值数组
vector<int> parseCards(string& s) {
    vector<int> cards;
    for(int i = 0; i < s.length(); i++) {
        if(s[i] >= '2' && s[i] <= '9') {
            cards.push_back(s[i] - '0');
        } else if(s[i] == '1') {
            if(i + 1 < s.length() && s[i + 1] == '0') {
                cards.push_back(10);
                i++;
            } else {
                return vector<int>();  // 非法输入
            }
        } else if(s[i] == 'J') cards.push_back(11);
        else if(s[i] == 'Q') cards.push_back(12);
        else if(s[i] == 'K') cards.push_back(13);
        else if(s[i] == 'A') cards.push_back(14);
        else return vector<int>();  // 非法输入
    }
    sort(cards.begin(), cards.end());
    return cards;
}

// 获取牌型(4=豹子,3=顺子,2=对子,1=普通牌)
pair<int, pair<int,int>> getType(vector<int>& cards) {
    if(cards[0] == cards[1] && cards[1] == cards[2]) {
        return {4, {cards[0], 0}};
    }
    if(cards[2] - cards[1] == 1 && cards[1] - cards[0] == 1) {
        return {3, {cards[0], 0}};
    }
    if(cards[0] == cards[1]) {
        return {2, {cards[0], cards[2]}};
    }
    if(cards[1] == cards[2]) {
        return {2, {cards[1], cards[0]}};
    }
    return {1, {0, 0}};
}

int compare(vector<int>& a, vector<int>& b) {
    if(a.empty() || b.empty()) return -2;  // 非法输入
    
    auto typeA = getType(a);
    auto typeB = getType(b);
    
    if(typeA.first > typeB.first) return 1;
    if(typeA.first < typeB.first) return -1;
    
    // 同牌型比较
    if(typeA.first == 4 || typeA.first == 3) {
        if(a[0] > b[0]) return 1;
        if(a[0] < b[0]) return -1;
        return 0;
    }
    if(typeA.first == 2) {
        if(typeA.second.first > typeB.second.first) return 1;
        if(typeA.second.first < typeB.second.first) return -1;
        if(typeA.second.second > typeB.second.second) return 1;
        if(typeA.second.second < typeB.second.second) return -1;
        return 0;
    }
    // 普通牌从大到小比较
    for(int i = 2; i >= 0; i--) {
        if(a[i] > b[i]) return 1;
        if(a[i] < b[i]) return -1;
    }
    return 0;
}

int main() {
    string s1, s2;
    while(cin >> s1 >> s2) {
        vector<int> cards1 = parseCards(s1);
        vector<int> cards2 = parseCards(s2);
        cout << compare(cards1, cards2) << endl;
    }
    return 0;
}
import java.util.*;

public class Main {
    // 将字符串转换为牌值数组
    static List<Integer> parseCards(String s) {
        List<Integer> cards = new ArrayList<>();
        for(int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(c >= '2' && c <= '9') {
                cards.add(c - '0');
            } else if(c == '1') {
                if(i + 1 < s.length() && s.charAt(i + 1) == '0') {
                    cards.add(10);
                    i++;
                } else {
                    return new ArrayList<>();  // 非法输入
                }
            } else if(c == 'J') cards.add(11);
            else if(c == 'Q') cards.add(12);
            else if(c == 'K') cards.add(13);
            else if(c == 'A') cards.add(14);
            else return new ArrayList<>();  // 非法输入
        }
        Collections.sort(cards);
        return cards;
    }
    
    static class CardType {
        int type;
        int pair;
        int other;
        
        CardType(int type, int pair, int other) {
            this.type = type;
            this.pair = pair;
            this.other = other;
        }
    }
    
    static CardType getType(List<Integer> cards) {
        if(cards.get(0).equals(cards.get(1)) && cards.get(1).equals(cards.get(2))) {
            return new CardType(4, cards.get(0), 0);
        }
        if(cards.get(2) - cards.get(1) == 1 && cards.get(1) - cards.get(0) == 1) {
            return new CardType(3, cards.get(0), 0);
        }
        if(cards.get(0).equals(cards.get(1))) {
            return new CardType(2, cards.get(0), cards.get(2));
        }
        if(cards.get(1).equals(cards.get(2))) {
            return new CardType(2, cards.get(1), cards.get(0));
        }
        return new CardType(1, 0, 0);
    }
    
    static int compare(List<Integer> a, List<Integer> b) {
        if(a.isEmpty() || b.isEmpty()) return -2;
        
        CardType typeA = getType(a);
        CardType typeB = getType(b);
        
        if(typeA.type != typeB.type) {
            return typeA.type > typeB.type ? 1 : -1;
        }
        
        if(typeA.type == 4 || typeA.type == 3) {
            if(a.get(0) > b.get(0)) return 1;
            if(a.get(0) < b.get(0)) return -1;
            return 0;
        }
        if(typeA.type == 2) {
            if(typeA.pair != typeB.pair) return typeA.pair > typeB.pair ? 1 : -1;
            if(typeA.other != typeB.other) return typeA.other > typeB.other ? 1 : -1;
            return 0;
        }
        for(int i = 2; i >= 0; i--) {
            if(!a.get(i).equals(b.get(i))) {
                return a.get(i) > b.get(i) ? 1 : -1;
            }
        }
        return 0;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            String s1 = sc.next();
            String s2 = sc.next();
            List<Integer> cards1 = parseCards(s1);
            List<Integer> cards2 = parseCards(s2);
            System.out.println(compare(cards1, cards2));
        }
    }
}
def parse_cards(s):
    cards = []
    i = 0
    while i < len(s):
        if '2' <= s[i] <= '9':
            cards.append(int(s[i]))
        elif s[i] == '1':
            if i + 1 < len(s) and s[i + 1] == '0':
                cards.append(10)
                i += 1
            else:
                return []  # 非法输入
        elif s[i] == 'J': cards.append(11)
        elif s[i] == 'Q': cards.append(12)
        elif s[i] == 'K': cards.append(13)
        elif s[i] == 'A': cards.append(14)
        else: return []  # 非法输入
        i += 1
    return sorted(cards)

def get_type(cards):
    if cards[0] == cards[1] == cards[2]:
        return (4, (cards[0], 0))
    if cards[2] - cards[1] == 1 and cards[1] - cards[0] == 1:
        return (3, (cards[0], 0))
    if cards[0] == cards[1]:
        return (2, (cards[0], cards[2]))
    if cards[1] == cards[2]:
        return (2, (cards[1], cards[0]))
    return (1, (0, 0))

def compare(a, b):
    if not a or not b: return -2  # 非法输入
    
    type_a = get_type(a)
    type_b = get_type(b)
    
    if type_a[0] != type_b[0]:
        return 1 if type_a[0] > type_b[0] else -1
        
    if type_a[0] in (3, 4):
        if a[0] > b[0]: return 1
        if a[0] < b[0]: return -1
        return 0
        
    if type_a[0] == 2:
        if type_a[1][0] != type_b[1][0]:
            return 1 if type_a[1][0] > type_b[1][0] else -1
        if type_a[1][1] != type_b[1][1]:
            return 1 if type_a[1][1] > type_b[1][1] else -1
        return 0
        
    # 普通牌从大到小比较
    for i in range(2, -1, -1):
        if a[i] != b[i]:
            return 1 if a[i] > b[i] else -1
    return 0

while True:
    try:
        s1, s2 = input().split()
        cards1 = parse_cards(s1)
        cards2 = parse_cards(s2)
        print(compare(cards1, cards2))
    except EOFError:
        break

算法及复杂度

  • 算法:排序 + 模拟
  • 时间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 每次比较只需处理固定数量的牌
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要存储固定数量的牌

题目链接

解题思路

这是一个字符串处理和验证问题。具体要求:

  1. 验证手机号是否合法,需要满足:
    • 长度为11位数字
    • 前三位为指定的运营商号段
  2. 根据号段判断运营商:
    • 电信:133,153,180,181,189
    • 联通:130,131,155,185,186
    • 移动:135,136,150,182,188
  3. 输出对应运营商名称,非法号码输出-1

代码

#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;

class PhoneValidator {
private:
    // 运营商号段集合
    unordered_set<string> telecom {"133", "153", "180", "181", "189"};
    unordered_set<string> unicom {"130", "131", "155", "185", "186"};
    unordered_set<string> mobile {"135", "136", "150", "182", "188"};
    
public:
    string validate(string phone) {
        // 检查长度
        if (phone.length() != 11) {
            return "-1";
        }
        
        // 获取前三位
        string prefix = phone.substr(0, 3);
        
        // 判断运营商
        if (telecom.count(prefix)) {
            return "China Telecom";
        }
        if (unicom.count(prefix)) {
            return "China Unicom";
        }
        if (mobile.count(prefix)) {
            return "China Mobile Communications";
        }
        
        return "-1";
    }
};

int main() {
    int t;
    cin >> t;
    PhoneValidator validator;
    
    while (t--) {
        string phone;
        cin >> phone;
        cout << validator.validate(phone) << endl;
    }
    return 0;
}
import java.util.*;

public class Main {
    // 运营商号段集合
    private static final Set<String> telecom = new HashSet<>(Arrays.asList(
        "133", "153", "180", "181", "189"));
    private static final Set<String> unicom = new HashSet<>(Arrays.asList(
        "130", "131", "155", "185", "186"));
    private static final Set<String> mobile = new HashSet<>(Arrays.asList(
        "135", "136", "150", "182", "188"));
    
    public static String validate(String phone) {
        // 检查长度
        if (phone.length() != 11) {
            return "-1";
        }
        
        // 获取前三位
        String prefix = phone.substring(0, 3);
        
        // 判断运营商
        if (telecom.contains(prefix)) {
            return "China Telecom";
        }
        if (unicom.contains(prefix)) {
            return "China Unicom";
        }
        if (mobile.contains(prefix)) {
            return "China Mobile Communications";
        }
        
        return "-1";
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        
        while (t-- > 0) {
            String phone = sc.next();
            System.out.println(validate(phone));
        }
    }
}
def validate_phone(phone: str) -> str:
    # 运营商号段集合
    telecom = {'133', '153', '180', '181', '189'}
    unicom = {'130', '131', '155', '185', '186'}
    mobile = {'135', '136', '150', '182', '188'}
    
    # 检查长度
    if len(phone) != 11:
        return "-1"
    
    # 获取前三位
    prefix = phone[:3]
    
    # 判断运营商
    if prefix in telecom:
        return "China Telecom"
    if prefix in unicom:
        return "China Unicom"
    if prefix in mobile:
        return "China Mobile Communications"
    
    return "-1"

def main():
    t = int(input())
    for _ in range(t):
        phone = input().strip()
        print(validate_phone(phone))

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:字符串处理 + 集合查找
  • 时间复杂度: O ( T ) \mathcal{O}(T) O(T) - T T T 为测试用例数量,每次验证为 O ( 1 ) \mathcal{O}(1) O(1)
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要存储固定的号段集合

题目链接

解题思路

这是一个贪心算法问题。需要找到能保证配对成功的最少手套数量,需要考虑单边缺失和双边都有的情况。

关键点:

  1. 区分单边缺失和双边都有的情况
  2. 记录每边手套的总数和最小值
  3. 贪心选择较少的一边
  4. 考虑配对成功的必要条件

算法步骤:

  1. 处理单边缺失的手套
  2. 统计双边都有时的手套数量
  3. 计算最优选择策略
  4. 确保能够配对成功

代码

class Gloves {
public:
    int findMinimum(int n, vector<int> left, vector<int> right) {
        int leftSum = 0, leftMin = INT_MAX;
        int rightSum = 0, rightMin = INT_MAX;
        int ret = 0;
        
        // 遍历所有颜色的手套
        for(int i = 0; i < n; ++i) {
            if(left[i] == 0 || right[i] == 0) {
                // 单边缺失的情况,必须全部拿走
                ret += left[i] + right[i];
            } else {
                // 双边都有的情况,更新总数和最小值
                leftMin = min(leftMin, left[i]);
                rightMin = min(rightMin, right[i]);
                leftSum += left[i];
                rightSum += right[i];
            }
        }
        
        // 选择较少的一边,并确保能配对成功
        ret += min(leftSum - leftMin + 1, rightSum - rightMin + 1) + 1;
        return ret;
    }
};
public class Gloves {
    public int findMinimum(int n, int[] left, int[] right) {
        int leftSum = 0, leftMin = Integer.MAX_VALUE;
        int rightSum = 0, rightMin = Integer.MAX_VALUE;
        int ret = 0;
        
        // 遍历所有颜色的手套
        for(int i = 0; i < n; i++) {
            if(left[i] == 0 || right[i] == 0) {
                // 单边缺失的情况,必须全部拿走
                ret += left[i] + right[i];
            } else {
                // 双边都有的情况,更新总数和最小值
                leftMin = Math.min(leftMin, left[i]);
                rightMin = Math.min(rightMin, right[i]);
                leftSum += left[i];
                rightSum += right[i];
            }
        }
        
        // 选择较少的一边,并确保能配对成功
        ret += Math.min(leftSum - leftMin + 1, rightSum - rightMin + 1) + 1;
        return ret;
    }
}
# -*- coding:utf-8 -*-
class Gloves:
    def findMinimum(self, n, left, right):
        leftSum, leftMin = 0, float('inf')
        rightSum, rightMin = 0, float('inf')
        ret = 0
        
        # 遍历所有颜色的手套
        for i in range(n):
            if left[i] == 0 or right[i] == 0:
                # 单边缺失的情况,必须全部拿走
                ret += left[i] + right[i]
            else:
                # 双边都有的情况,更新总数和最小值
                leftMin = min(leftMin, left[i])
                rightMin = min(rightMin, right[i])
                leftSum += left[i]
                rightSum += right[i]
        
        # 选择较少的一边,并确保能配对成功
        ret += min(leftSum - leftMin + 1, rightSum - rightMin + 1) + 1
        return ret

算法及复杂度

  • 算法:贪心算法
  • 时间复杂度: O ( n ) \mathcal{O(n)} O(n),只需遍历一次数组
  • 空间复杂度: O ( 1 ) \mathcal{O(1)} O(1),只需要常数级额外空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值