题目## 题目## 题目## 题目
#题解
##题目难度:中等难度
###难点分析:
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>>a[i];
}
cin>>m;
sort(a,a+4);
do{
for(int i=1;i<=4;i++){
for(int j=1;j<=4;j++){
for(int k=1;k<=4;k++){
s.push(a[0]);
int b[3];
b[0]=i;b[1]=j;b[2]=k;
for(int x=0;x<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>=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<</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) - 只需要存储固定数量的牌
解题思路
这是一个字符串处理和验证问题。具体要求:
- 验证手机号是否合法,需要满足:
- 长度为11位数字
- 前三位为指定的运营商号段
- 根据号段判断运营商:
- 电信:133,153,180,181,189
- 联通:130,131,155,185,186
- 移动:135,136,150,182,188
- 输出对应运营商名称,非法号码输出-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) - 只需要存储固定的号段集合
解题思路
这是一个贪心算法问题。需要找到能保证配对成功的最少手套数量,需要考虑单边缺失和双边都有的情况。
关键点:
- 区分单边缺失和双边都有的情况
- 记录每边手套的总数和最小值
- 贪心选择较少的一边
- 考虑配对成功的必要条件
算法步骤:
- 处理单边缺失的手套
- 统计双边都有时的手套数量
- 计算最优选择策略
- 确保能够配对成功
代码
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),只需要常数级额外空间

被折叠的 条评论
为什么被折叠?



