第16章 C++面试算法与数据库编程实战
第16章 算法与数据库编程实战
16.1 基础算法问题精解
面试题188 斐波那契数列的多种实现方法
斐波那契数列是经典的递归问题,其定义如下:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2)。在实际编程中,我们需要考虑不同实现方式的性能差异。
递归实现是最直观的方法,但存在重复计算问题,时间复杂度为O(2^n):
#include <iostream>
using namespace std;
class FibonacciCalculator
{
public:
long long fibonacciRecursive(int n)
{
if (n <= 0)
{
return 0;
}
if (n == 1)
{
return 1;
}
return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
}
};
int main()
{
FibonacciCalculator calculator;
int n = 10;
cout << "斐波那契数列第" << n << "项(递归):"
<< calculator.fibonacciRecursive(n) << endl;
return 0;
}
迭代实现通过保存中间结果避免重复计算,时间复杂度降为O(n):
#include <iostream>
#include <vector>
using namespace std;
class FibonacciCalculator
{
public:
long long fibonacciIterative(int n)
{
if (n <= 0)
{
return 0;
}
if (n == 1)
{
return 1;
}
long long prev = 0;
long long curr = 1;
for (int i = 2; i <= n; i++)
{
long long next = prev + curr;
prev = curr;
curr = next;
}
return curr;
}
vector<long long> generateSequence(int count)
{
vector<long long> sequence;
if (count <= 0)
{
return sequence;
}
sequence.push_back(0);
if (count == 1)
{
return sequence;
}
sequence.push_back(1);
for (int i = 2; i < count; i++)
{
long long next = sequence[i-1] + sequence[i-2];
sequence.push_back(next);
}
return sequence;
}
};
int main()
{
FibonacciCalculator calculator;
int n = 10;
cout << "斐波那契数列第" << n << "项(迭代):"
<< calculator.fibonacciIterative(n) << endl;
vector<long long> sequence = calculator.generateSequence(n);
cout << "前" << n << "项斐波那契数列:";
for (long long num : sequence)
{
cout << num << " ";
}
cout << endl;
return 0;
}
矩阵快速幂实现将时间复杂度进一步优化到O(log n),适用于大数计算:
#include <iostream>
#include <vector>
using namespace std;
class MatrixFibonacci
{
private:
// 2x2矩阵乘法
vector<vector<long long>> matrixMultiply(
const vector<vector<long long>>& A,
const vector<vector<long long>>& B)
{
vector<vector<long long>> result(2, vector<long long>(2, 0));
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
result[i][j] += A[i][k] * B[k][j];
}
}
}
return result;
}
// 矩阵快速幂
vector<vector<long long>> matrixPower(int n)
{
vector<vector<long long>> base = {{1, 1}, {1, 0}};
vector<vector<long long>> result = {{1, 0}, {0, 1}}; // 单位矩阵
while (n > 0)
{
if (n % 2 == 1)
{
result = matrixMultiply(result, base);
}
base = matrixMultiply(base, base);
n /= 2;
}
return result;
}
public:
long long fibonacciMatrix(int n)
{
if (n <= 0)
{
return 0;
}
vector<vector<long long>> result = matrixPower(n - 1);
return result[0][0];
}
};
int main()
{
MatrixFibonacci calculator;
int n = 10;
cout << "斐波那契数列第" << n << "项(矩阵快速幂):"
<< calculator.fibonacciMatrix(n) << endl;
return 0;
}
面试题189 杨辉三角的构建与应用
杨辉三角是二项式系数在三角形中的几何排列,每个数等于它上方两数之和。
理论基础:
- 第n行有n个元素
- 每行第一个和最后一个元素为1
- 其他元素满足:triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]
#include <iostream>
#include <vector>
using namespace std;
class PascalTriangle
{
public:
vector<vector<int>> generateTriangle(int numRows)
{
vector<vector<int>> triangle;
if (numRows <= 0)
{
return triangle;
}
// 第一行
triangle.push_back({1});
if (numRows == 1)
{
return triangle;
}
for (int i = 1; i < numRows; i++)
{
vector<int> row;
row.push_back(1); // 每行第一个元素
for (int j = 1; j < i; j++)
{
int value = triangle[i-1][j-1] + triangle[i-1][j];
row.push_back(value);
}
row.push_back(1); // 每行最后一个元素
triangle.push_back(row);
}
return triangle;
}
void printTriangle(const vector<vector<int>>& triangle)
{
int numRows = triangle.size();
for (int i = 0; i < numRows; i++)
{
// 打印前导空格实现居中效果
for (int space = 0; space < numRows - i - 1; space++)
{
cout << " ";
}
for (int j = 0; j <= i; j++)
{
cout << triangle[i][j] << " ";
}
cout << endl;
}
}
// 获取特定位置的二项式系数 C(n, k)
int getBinomialCoefficient(int n, int k)
{
if (k < 0 || k > n)
{
return 0;
}
if (k == 0 || k == n)
{
return 1;
}
// 使用组合公式 C(n, k) = n! / (k! * (n-k)!)
// 为避免溢出,使用迭代计算
long long result = 1;
if (k > n - k)
{
k = n - k; // 利用对称性
}
for (int i = 0; i < k; i++)
{
result = result * (n - i) / (i + 1);
}
return result;
}
};
int main()
{
PascalTriangle pascal;
int numRows = 6;
vector<vector<int>> triangle = pascal.generateTriangle(numRows);
cout << "杨辉三角(" << numRows << "行):" << endl;
pascal.printTriangle(triangle);
int n = 5, k = 2;
cout << "二项式系数 C(" << n << ", " << k << ") = "
<< pascal.getBinomialCoefficient(n, k) << endl;
return 0;
}
面试题190 整数十进制转二进制的多种算法
十进制转二进制是基础的数字系统转换问题,有多种实现方法。
除二取余法是最常用的方法:
#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
using namespace std;
class DecimalToBinaryConverter
{
public:
// 方法1:使用除二取余法
string decimalToBinaryBasic(int decimal)
{
if (decimal == 0)
{
return "0";
}
string binary;
bool isNegative = false;
// 处理负数(使用补码表示)
if (decimal < 0)
{
isNegative = true;
decimal = -decimal;
}
while (decimal > 0)
{
binary += (decimal % 2) ? '1' : '0';
decimal /= 2;
}
reverse(binary.begin(), binary.end());
if (isNegative)
{
// 简单处理:添加负号,实际应用中应使用补码
binary = "-" + binary;
}
return binary;
}
// 方法2:使用位运算(更高效)
string decimalToBinaryBitwise(int decimal)
{
if (decimal == 0)
{
return "0";
}
const int BITS = 32; // 32位整数
string binary;
for (int i = BITS - 1; i >= 0; i--)
{
int bit = (decimal >> i) & 1;
binary += (bit ? '1' : '0');
}
// 去除前导零
size_t pos = binary.find('1');
if (pos != string::npos)
{
binary = binary.substr(pos);
}
else
{
binary = "0";
}
return binary;
}
// 方法3:使用标准库bitset
string decimalToBinaryBitset(int decimal)
{
bitset<32> bits(decimal);
string binary = bits.to_string();
// 去除前导零
size_t pos = binary.find('1');
if (pos != string::npos)
{
binary = binary.substr(pos);
}
else
{
binary = "0";
}
return binary;
}
// 二进制转十进制
int binaryToDecimal(const string& binary)
{
int decimal = 0;
int length = binary.length();
for (int i = 0; i < length; i++)
{
if (binary[i] == '1')
{
decimal = decimal * 2 + 1;
}
else if (binary[i] == '0')
{
decimal = decimal * 2;
}
else
{
throw invalid_argument("无效的二进制字符串");
}
}
return decimal;
}
};
int main()
{
DecimalToBinaryConverter converter;
int decimal = 42;
cout << "十进制数 " << decimal << " 的二进制表示:" << endl;
cout << "除二取余法: " << converter.decimalToBinaryBasic(decimal) << endl;
cout << "位运算法: " << converter.decimalToBinaryBitwise(decimal) << endl;
cout << "bitset法: " << converter.decimalToBinaryBitset(decimal) << endl;
string binary = "101010";
cout << "二进制数 " << binary << " 的十进制表示: "
<< converter.binaryToDecimal(binary) << endl;
return 0;
}
面试题191 素数判定与生成算法
素数(质数)是大于1且只能被1和自身整除的自然数,在密码学等领域有重要应用。
基础素数判定:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
class PrimeNumber
{
public:
// 基础素数判定(试除法)
bool isPrimeBasic(int n)
{
if (n <= 1)
{
return false;
}
if (n == 2)
{
return true;
}
if (n % 2 == 0)
{
return false;
}
// 检查从3到sqrt(n)的奇数
for (int i = 3; i * i <= n; i += 2)
{
if (n % i == 0)
{
return false;
}
}
return true;
}
// 埃拉托斯特尼筛法生成素数表
vector<int> generatePrimesSieve(int limit)
{
vector<bool> isPrime(limit + 1, true);
vector<int> primes;
if (limit < 2)
{
return primes;
}
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= limit; i++)
{
if (isPrime[i])
{
for (int j = i * i; j <= limit; j += i)
{
isPrime[j] = false;
}
}
}
for (int i = 2; i <= limit; i++)
{
if (isPrime[i])
{
primes.push_back(i);
}
}
return primes;
}
// 优化版筛法(奇数筛)
vector<int> generatePrimesOptimized(int limit)
{
if (limit < 2)
{
return {};
}
vector<bool> isPrime(limit + 1, true);
vector<int> primes = {2};
// 只处理奇数
for (int i = 3; i <= limit; i += 2)
{
if (isPrime[i])
{
primes.push_back(i);
if ((long long)i * i <= limit)
{
for (int j = i * i; j <= limit; j += 2 * i)
{
isPrime[j] = false;
}
}
}
}
return primes;
}
// 分解质因数
vector<pair<int, int>> primeFactorization(int n)
{
vector<pair<int, int>> factors;
if (n <= 1)
{
return factors;
}
// 处理2的因子
int count = 0;
while (n % 2 == 0)
{
count++;
n /= 2;
}
if (count > 0)
{
factors.push_back({2, count});
}
// 处理奇数因子
for (int i = 3; i * i <= n; i += 2)
{
count = 0;
while (n % i == 0)
{
count++;
n /= i;
}
if (count > 0)
{
factors.push_back({i, count});
}
}
// 处理剩余的质数
if (n > 1)
{
factors.push_back({n, 1});
}
return factors;
}
};
int main()
{
PrimeNumber prime;
int testNumber = 97;
cout << testNumber << " 是素数吗? "
<< (prime.isPrimeBasic(testNumber) ? "是" : "否") << endl;
int limit = 100;
vector<int> primes = prime.generatePrimesSieve(limit);
cout << "小于等于 " << limit << " 的素数:" << endl;
for (int i = 0; i < primes.size(); i++)
{
cout << primes[i];
if (i < primes.size() - 1)
{
cout << ", ";
}
if ((i + 1) % 10 == 0)
{
cout << endl;
}
}
cout << endl;
int factorNumber = 84;
vector<pair<int, int>> factors = prime.primeFactorization(factorNumber);
cout << factorNumber << " 的质因数分解:";
for (size_t i = 0; i < factors.size(); i++)
{
cout << factors[i].first;
if (factors[i].second > 1)
{
cout << "^" << factors[i].second;
}
if (i < factors.size() - 1)
{
cout << " × ";
}
}
cout << endl;
return 0;
}
面试题192 字符串与整数的相互转换
字符串与整数的转换是常见的编程任务,需要处理边界条件和错误情况。
#include <iostream>
#include <string>
#include <climits>
#include <stdexcept>
using namespace std;
class StringIntConverter
{
public:
// 字符串转整数(支持负数)
int stringToInt(const string& str)
{
if (str.empty())
{
throw invalid_argument("空字符串");
}
int index = 0;
int sign = 1;
int result = 0;
// 跳过前导空格
while (index < str.length() && str[index] == ' ')
{
index++;
}
// 处理符号
if (index < str.length() && (str[index] == '+' || str[index] == '-'))
{
sign = (str[index] == '-') ? -1 : 1;
index++;
}
// 转换数字
while (index < str.length() && isdigit(str[index]))
{
int digit = str[index] - '0';
// 检查溢出
if (result > INT_MAX / 10 ||
(result == INT_MAX / 10 && digit > INT_MAX % 10))
{
return (sign == 1) ? INT_MAX : INT_MIN;
}
result = result * 10 + digit;
index++;
}
return sign * result;
}
// 整数转字符串
string intToString(int num)
{
if (num == 0)
{
return "0";
}
string result;
bool isNegative = false;
// 处理负数
if (num < 0)
{
isNegative = true;
// 注意:INT_MIN取反会溢出,需要特殊处理
if (num == INT_MIN)
{
return "-2147483648";
}
num = -num;
}
// 逐位转换
while (num > 0)
{
char digit = '0' + (num % 10);
result = digit + result;
num /= 10;
}
if (isNegative)
{
result = "-" + result;
}
return result;
}
// 增强版:支持不同进制(2-36)
string intToStringWithBase(int num, int base = 10)
{
if (base < 2 || base > 36)
{
throw invalid_argument("进制必须在2-36之间");
}
if (num == 0)
{
return "0";
}
const string DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string result;
bool isNegative = false;
if (num < 0 && base == 10)
{
isNegative = true;
num = -num;
}
unsigned int unum = num; // 使用无符号数避免负数问题
while (unum > 0)
{
result = DIGITS[unum % base] + result;
unum /= base;
}
if (isNegative)
{
result = "-" + result;
}
return result;
}
};
int main()
{
StringIntConverter converter;
// 测试字符串转整数
vector<string> testStrings = {"42", " -123", "4193 with words", "0", "-2147483648"};
for (const string& str : testStrings)
{
try
{
int result = converter.stringToInt(str);
cout << "字符串 \"" << str << "\" 转换为整数: " << result << endl;
}
catch (const exception& e)
{
cout << "字符串 \"" << str << "\" 转换错误: " << e.what() << endl;
}
}
// 测试整数转字符串
vector<int> testInts = {42, -123, 0, INT_MAX, INT_MIN};
for (int num : testInts)
{
string result = converter.intToString(num);
cout << "整数 " << num << " 转换为字符串: \"" << result << "\"" << endl;
}
// 测试不同进制
int number = 255;
cout << "数字 " << number << " 在不同进制下的表示:" << endl;
for (int base = 2; base <= 16; base++)
{
string result = converter.intToStringWithBase(number, base);
cout << "基数 " << base << ": " << result << endl;
}
return 0;
}
16.2 数据库操作实践
面试题193 选课系统设计与实现
选课系统是典型的多表关系数据库应用,涉及学生、课程和选课记录等实体。
数据库设计:
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <memory>
using namespace std;
// 简单的内存数据库模拟
class InMemoryDatabase
{
private:
map<int, string> students;
map<int, pair<string, int>> courses; // 课程ID -> (课程名, 容量)
map<pair<int, int>, string> enrollments; // (学生ID, 课程ID) -> 成绩
int nextStudentId = 1;
int nextCourseId = 1;
public:
// 学生管理
int addStudent(const string& name)
{
students[nextStudentId] = name;
return nextStudentId++;
}
string getStudentName(int studentId)
{
auto it = students.find(studentId);
return (it != students.end()) ? it->second : "未知学生";
}
// 课程管理
int addCourse(const string& name, int capacity)
{
courses[nextCourseId] = {name, capacity};
return nextCourseId++;
}
string getCourseName(int courseId)
{
auto it = courses.find(courseId);
return (it != courses.end()) ? it->second.first : "未知课程";
}
int getCourseCapacity(int courseId)
{
auto it = courses.find(courseId);
return (it != courses.end()) ? it->second.second : 0;
}
// 选课功能
bool enrollStudent(int studentId, int courseId)
{
// 检查学生和课程是否存在
if (students.find(studentId) == students.end() ||
courses.find(courseId) == courses.end())
{
return false;
}
// 检查是否已经选过该课程
if (enrollments.find({studentId, courseId}) != enrollments.end())
{
return false;
}
// 检查课程容量
int currentEnrollment = 0;
for (const auto& enrollment : enrollments)
{
if (enrollment.first.second == courseId)
{
currentEnrollment++;
}
}
if (currentEnrollment >= getCourseCapacity(courseId))
{
return false;
}
// 成功选课
enrollments[{studentId, courseId}] = ""; // 初始成绩为空
return true;
}
// 成绩管理
bool setGrade(int studentId, int courseId, const string& grade)
{
auto key = make_pair(studentId, courseId);
if (enrollments.find(key) != enrollments.end())
{
enrollments[key] = grade;
return true;
}
return false;
}
string getGrade(int studentId, int courseId)
{
auto key = make_pair(studentId, courseId);
auto it = enrollments.find(key);
return (it != enrollments.end()) ? it->second : "未选课";
}
// 查询功能
vector<int> getStudentCourses(int studentId)
{
vector<int> result;
for (const auto& enrollment : enrollments)
{
if (enrollment.first.first == studentId)
{
result.push_back(enrollment.first.second);
}
}
return result;
}
vector<int> getCourseStudents(int courseId)
{
vector<int> result;
for (const auto& enrollment : enrollments)
{
if (enrollment.first.second == courseId)
{
result.push_back(enrollment.first.first);
}
}
return result;
}
// 统计功能
void printDatabaseStatus()
{
cout << "=== 数据库状态 ===" << endl;
cout << "学生总数: " << students.size() << endl;
cout << "课程总数: " << courses.size() << endl;
cout << "选课记录总数: " << enrollments.size() << endl;
for (const auto& course : courses)
{
int enrollmentCount = getCourseStudents(course.first).size();
cout << "课程 '" << course.second.first << "' 选课人数: "
<< enrollmentCount << "/" << course.second.second << endl;
}
cout << "=================" << endl;
}
};
// 选课系统业务逻辑层
class CourseSelectionSystem
{
private:
unique_ptr<InMemoryDatabase> database;
public:
CourseSelectionSystem() : database(make_unique<InMemoryDatabase>()) {}
// 初始化测试数据
void initializeTestData()
{
// 添加学生
int student1 = database->addStudent("张三");
int student2 = database->addStudent("李四");
int student3 = database->addStudent("王五");
// 添加课程
int course1 = database->addCourse("高等数学", 2);
int course2 = database->addCourse("程序设计", 3);
int course3 = database->addCourse("数据结构", 2);
cout << "测试数据初始化完成" << endl;
}
// 学生选课
void studentEnrollCourse(int studentId, int courseId)
{
if (database->enrollStudent(studentId, courseId))
{
cout << database->getStudentName(studentId) << " 成功选课: "
<< database->getCourseName(courseId) << endl;
}
else
{
cout << database->getStudentName(studentId) << " 选课失败: "
<< database->getCourseName(courseId) << endl;
}
}
// 教师录入成绩
void teacherInputGrade(int studentId, int courseId, const string& grade)
{
if (database->setGrade(studentId, courseId, grade))
{
cout << "成功为 " << database->getStudentName(studentId)
<< " 的课程 '" << database->getCourseName(courseId)
<< "' 录入成绩: " << grade << endl;
}
else
{
cout << "成绩录入失败" << endl;
}
}
// 查询学生选课情况
void queryStudentCourses(int studentId)
{
cout << database->getStudentName(studentId) << " 的选课情况:" << endl;
vector<int> courses = database->getStudentCourses(studentId);
if (courses.empty())
{
cout << " 未选任何课程" << endl;
}
else
{
for (int courseId : courses)
{
string grade = database->getGrade(studentId, courseId);
cout << " 课程: " << database->getCourseName(courseId)
<< ", 成绩: " << (grade.empty() ? "未出成绩" : grade) << endl;
}
}
}
// 查询课程选课学生
void queryCourseStudents(int courseId)
{
cout << "课程 '" << database->getCourseName(courseId) << "' 的选课学生:" << endl;
vector<int> students = database->getCourseStudents(courseId);
if (students.empty())
{
cout << " 暂无学生选课" << endl;
}
else
{
for (int studentId : students)
{
string grade = database->getGrade(studentId, courseId);
cout << " 学生: " << database->getStudentName(studentId)
<< ", 成绩: " << (grade.empty() ? "未出成绩" : grade) << endl;
}
}
}
void printSystemStatus()
{
database->printDatabaseStatus();
}
};
int main()
{
CourseSelectionSystem system;
// 初始化测试数据
system.initializeTestData();
cout << endl;
// 模拟选课过程
cout << "=== 选课过程模拟 ===" << endl;
system.studentEnrollCourse(1, 1); // 张三选高等数学
system.studentEnrollCourse(1, 2); // 张三选程序设计
system.studentEnrollCourse(2, 1); // 李四选高等数学
system.studentEnrollCourse(2, 2); // 李四选程序设计
system.studentEnrollCourse(3, 1); // 王五选高等数学(应该失败,容量已满)
system.studentEnrollCourse(3, 2); // 王五选程序设计
system.studentEnrollCourse(3, 3); // 王五选数据结构
cout << endl;
// 模拟成绩录入
cout << "=== 成绩录入模拟 ===" << endl;
system.teacherInputGrade(1, 1, "A");
system.teacherInputGrade(1, 2, "B+");
system.teacherInputGrade(2, 1, "B");
system.teacherInputGrade(2, 2, "A-");
system.teacherInputGrade(3, 2, "C+");
system.teacherInputGrade(3, 3, "A");
cout << endl;
// 查询功能演示
cout << "=== 查询功能演示 ===" << endl;
system.queryStudentCourses(1);
cout << endl;
system.queryStudentCourses(2);
cout << endl;
system.queryStudentCourses(3);
cout << endl;
system.queryCourseStudents(1);
cout << endl;
system.queryCourseStudents(2);
cout << endl;
// 系统状态
system.printSystemStatus();
return 0;
}
第17章 算法思维拓展与面试技巧
17.1 经典算法问题深入解析
面试题194 八皇后问题的回溯解法
八皇后问题要求在8×8棋盘上放置8个皇后,使得它们互不攻击(即任意两个皇后都不在同一行、同一列或同一对角线上)。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class EightQueensSolver
{
private:
vector<vector<string>> solutions;
bool isValid(const vector<string>& board, int row, int col, int n)
{
// 检查同一列
for (int i = 0; i < row; i++)
{
if (board[i][col] == 'Q')
{
return false;
}
}
// 检查左上对角线
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--)
{
if (board[i][j] == 'Q')
{
return false;
}
}
// 检查右上对角线
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++)
{
if (board[i][j] == 'Q')
{
return false;
}
}
return true;
}
void backtrack(vector<string>& board, int row, int n)
{
if (row == n)
{
solutions.push_back(board);
return;
}
for (int col = 0; col < n; col++)
{
if (isValid(board, row, col, n))
{
board[row][col] = 'Q';
backtrack(board, row + 1, n);
board[row][col] = '.';
}
}
}
public:
vector<vector<string>> solveNQueens(int n)
{
solutions.clear();
vector<string> board(n, string(n, '.'));
backtrack(board, 0, n);
return solutions;
}
void printSolutions(int n = 8)
{
auto allSolutions = solveNQueens(n);
cout << n << "皇后问题共有 " << allSolutions.size() << " 种解法" << endl;
// 打印前3种解法(如果存在)
int count = min(3, (int)allSolutions.size());
for (int i = 0; i < count; i++)
{
cout << "解法 " << (i + 1) << ":" << endl;
for (const string& row : allSolutions[i])
{
for (char cell : row)
{
cout << cell << " ";
}
cout << endl;
}
cout << endl;
}
}
};
int main()
{
EightQueensSolver solver;
solver.printSolutions(8);
return 0;
}
面试题195 最大矩形面积问题
给定一个由0和1组成的二维矩阵,找出只包含1的最大矩形,并返回其面积。
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
class MaxRectangleFinder
{
public:
int maximalRectangle(vector<vector<char>>& matrix)
{
if (matrix.empty() || matrix[0].empty())
{
return 0;
}
int rows = matrix.size();
int cols = matrix[0].size();
vector<int> heights(cols + 1, 0); // 多加一列用于处理边界
int maxArea = 0;
for (int i = 0; i < rows; i++)
{
// 更新高度数组
for (int j = 0; j < cols; j++)
{
if (matrix[i][j] == '1')
{
heights[j] += 1;
}
else
{
heights[j] = 0;
}
}
// 计算当前行的最大矩形面积
maxArea = max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
private:
int largestRectangleArea(vector<int>& heights)
{
stack<int> st;
int maxArea = 0;
int n = heights.size();
for (int i = 0; i < n; i++)
{
while (!st.empty() && heights[i] < heights[st.top()])
{
int height = heights[st.top()];
st.pop();
int width = st.empty() ? i : i - st.top() - 1;
maxArea = max(maxArea, height * width);
}
st.push(i);
}
return maxArea;
}
};
int main()
{
MaxRectangleFinder finder;
vector<vector<char>> matrix = {
{'1', '0', '1', '0', '0'},
{'1', '0', '1', '1', '1'},
{'1', '1', '1', '1', '1'},
{'1', '0', '0', '1', '0'}
};
int maxArea = finder.maximalRectangle(matrix);
cout << "最大矩形面积为: " << maxArea << endl;
// 可视化矩阵
cout << "输入矩阵:" << endl;
for (const auto& row : matrix)
{
for (char cell : row)
{
cout << cell << " ";
}
cout << endl;
}
return 0;
}
面试题196 汉诺塔问题的递归解法
汉诺塔问题是经典的递归问题,涉及将盘子从一个柱子移动到另一个柱子,遵守移动规则。
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class HanoiTowerSolver
{
private:
int moveCount;
void moveDisk(int n, char from, char to, char aux)
{
if (n == 1)
{
cout << "将盘 1 从 " << from << " 移动到 " << to << endl;
moveCount++;
return;
}
moveDisk(n - 1, from, aux, to);
cout << "将盘 " << n << " 从 " << from << " 移动到 " << to << endl;
moveCount++;
moveDisk(n - 1, aux, to, from);
}
public:
HanoiTowerSolver() : moveCount(0) {}
void solveHanoi(int n)
{
if (n <= 0)
{
cout << "盘子数量必须大于0" << endl;
return;
}
cout << "解决 " << n << " 个盘子的汉诺塔问题:" << endl;
moveCount = 0;
moveDisk(n, 'A', 'C', 'B');
cout << "总移动次数: " << moveCount << " (理论最小值: " << ( (1 << n) - 1 ) << ")" << endl;
}
// 迭代解法(使用栈模拟)
void solveHanoiIterative(int n)
{
if (n <= 0)
{
return;
}
struct Move
{
int n;
char from, to, aux;
bool expanded;
};
stack<Move> st;
st.push({n, 'A', 'C', 'B', false});
moveCount = 0;
cout << "迭代解法 - " << n << " 个盘子:" << endl;
while (!st.empty())
{
Move current = st.top();
st.pop();
if (current.n == 1)
{
cout << "将盘 1 从 " << current.from << " 移动到 " << current.to << endl;
moveCount++;
}
else
{
if (!current.expanded)
{
// 第一次处理这个状态,展开为子问题
st.push({current.n, current.from, current.to, current.aux, true});
st.push({current.n - 1, current.from, current.aux, current.to, false});
}
else
{
// 已经展开过,现在执行移动
cout << "将盘 " << current.n << " 从 " << current.from << " 移动到 " << current.to << endl;
moveCount++;
st.push({current.n - 1, current.aux, current.to, current.from, false});
}
}
}
cout << "总移动次数: " << moveCount << endl;
}
};
int main()
{
HanoiTowerSolver solver;
cout << "=== 递归解法 ===" << endl;
solver.solveHanoi(3);
cout << endl << "=== 迭代解法 ===" << endl;
solver.solveHanoiIterative(3);
return 0;
}
面试题197 逻辑推理问题:新娘和新郎
这是经典逻辑推理问题,需要根据条件推断正确配对。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MarriageProblemSolver
{
public:
void solveMarriageProblem()
{
// 三对新郎新娘:A,B,C 和 X,Y,Z
vector<char> grooms = {'A', 'B', 'C'};
vector<char> brides = {'X', 'Y', 'Z'};
// 生成所有可能的配对
vector<vector<pair<char, char>>> allPairings;
vector<char> temp = brides;
do
{
vector<pair<char, char>> pairing;
for (size_t i = 0; i < grooms.size(); i++)
{
pairing.push_back({grooms[i], temp[i]});
}
allPairings.push_back(pairing);
}
while (next_permutation(temp.begin(), temp.end()));
// 应用条件过滤
vector<vector<pair<char, char>>> validSolutions;
for (const auto& pairing : allPairings)
{
if (satisfiesConditions(pairing))
{
validSolutions.push_back(pairing);
}
}
// 输出结果
cout << "新娘新郎配对问题解决方案:" << endl;
if (validSolutions.empty())
{
cout << "无解" << endl;
}
else
{
for (size_t i = 0; i < validSolutions.size(); i++)
{
cout << "解决方案 " << (i + 1) << ":" << endl;
for (const auto& couple : validSolutions[i])
{
cout << " 新郎 " << couple.first << " 娶新娘 " << couple.second << endl;
}
}
}
}
private:
bool satisfiesConditions(const vector<pair<char, char>>& pairing)
{
// 条件1:A不与X结婚
for (const auto& couple : pairing)
{
if (couple.first == 'A' && couple.second == 'X')
{
return false;
}
}
// 条件2:X不与C结婚
for (const auto& couple : pairing)
{
if (couple.first == 'C' && couple.second == 'X')
{
return false;
}
}
// 条件3:C不与Z结婚
for (const auto& couple : pairing)
{
if (couple.first == 'C' && couple.second == 'Z')
{
return false;
}
}
return true;
}
};
int main()
{
MarriageProblemSolver solver;
solver.solveMarriageProblem();
return 0;
}
面试题198 大数乘法算法实现
处理超出基本数据类型范围的大数乘法。
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class BigNumberMultiplier
{
public:
string multiply(string num1, string num2)
{
if (num1 == "0" || num2 == "0")
{
return "0";
}
int m = num1.size();
int n = num2.size();
vector<int> result(m + n, 0);
// 从低位到高位逐位相乘
for (int i = m - 1; i >= 0; i--)
{
for (int j = n - 1; j >= 0; j--)
{
int mul = (num1[i] - '0') * (num2[j] - '0');
int sum = mul + result[i + j + 1];
result[i + j + 1] = sum % 10;
result[i + j] += sum / 10;
}
}
// 转换为字符串
string product;
for (int num : result)
{
if (!(product.empty() && num == 0))
{
product += to_string(num);
}
}
return product.empty() ? "0" : product;
}
// 使用Karatsuba算法(分治法)
string karatsubaMultiply(string num1, string num2)
{
// 确保字符串长度相等且为2的幂(简化实现)
int n = max(num1.size(), num2.size());
while (num1.size() < n) num1 = "0" + num1;
while (num2.size() < n) num2 = "0" + num2;
if (n == 0)
{
return "0";
}
if (n == 1)
{
return to_string((num1[0] - '0') * (num2[0] - '0'));
}
int half = n / 2;
string a = num1.substr(0, half);
string b = num1.substr(half);
string c = num2.substr(0, half);
string d = num2.substr(half);
string ac = karatsubaMultiply(a, c);
string bd = karatsubaMultiply(b, d);
string abcd = karatsubaMultiply(addStrings(a, b), addStrings(c, d));
string adbc = subtractStrings(subtractStrings(abcd, ac), bd);
// 结果 = ac * 10^(2*half) + adbc * 10^half + bd
for (int i = 0; i < 2 * half; i++)
{
ac += "0";
}
for (int i = 0; i < half; i++)
{
adbc += "0";
}
return addStrings(addStrings(ac, adbc), bd);
}
private:
string addStrings(string num1, string num2)
{
string result;
int carry = 0;
int i = num1.size() - 1;
int j = num2.size() - 1;
while (i >= 0 || j >= 0 || carry > 0)
{
int sum = carry;
if (i >= 0)
{
sum += num1[i--] - '0';
}
if (j >= 0)
{
sum += num2[j--] - '0';
}
result += to_string(sum % 10);
carry = sum / 10;
}
reverse(result.begin(), result.end());
return result;
}
string subtractStrings(string num1, string num2)
{
// 简化实现,假设num1 >= num2
string result;
int borrow = 0;
int i = num1.size() - 1;
int j = num2.size() - 1;
while (i >= 0)
{
int digit1 = num1[i--] - '0' - borrow;
int digit2 = (j >= 0) ? num2[j--] - '0' : 0;
if (digit1 < digit2)
{
digit1 += 10;
borrow = 1;
}
else
{
borrow = 0;
}
result += to_string(digit1 - digit2);
}
reverse(result.begin(), result.end());
// 去除前导零
size_t pos = result.find_first_not_of('0');
return (pos != string::npos) ? result.substr(pos) : "0";
}
};
int main()
{
BigNumberMultiplier multiplier;
string num1 = "123456789";
string num2 = "987654321";
cout << "大数乘法测试:" << endl;
cout << num1 << " × " << num2 << " = " << endl;
string result1 = multiplier.multiply(num1, num2);
cout << "标准算法: " << result1 << endl;
// 验证结果
cout << "验证: " << endl;
cout << "123456789 × 987654321 = 121932631112635269" << endl;
// 更大数的测试
string bigNum1 = "12345678901234567890";
string bigNum2 = "98765432109876543210";
string result2 = multiplier.multiply(bigNum1, bigNum2);
cout << bigNum1 << " × " << bigNum2 << " = " << endl;
cout << result2 << endl;
return 0;
}
17.2 面试经验与技巧分享
17.2.1 技术面试准备策略
技术面试的成功不仅取决于技术能力,还与准备策略和面试技巧密切相关。以下是一些有效的准备方法:
算法与数据结构复习:
- 重点掌握数组、链表、栈、队列、哈希表、树、图等基础数据结构
- 熟练运用排序、搜索、动态规划、回溯、分治等算法思想
- 每天坚持解决2-3道LeetCode中等难度问题
系统设计准备:
- 理解常见系统设计模式:MVC、微服务、事件驱动等
- 掌握数据库设计原则和优化技巧
- 学习分布式系统基础概念:负载均衡、缓存、消息队列等
// 面试中常见的白板编码示例:实现LRU缓存
#include <iostream>
#include <unordered_map>
using namespace std;
struct LRUNode
{
int key;
int value;
LRUNode* prev;
LRUNode* next;
LRUNode(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};
class LRUCache
{
private:
int capacity;
unordered_map<int, LRUNode*> cache;
LRUNode* head;
LRUNode* tail;
void addToHead(LRUNode* node)
{
node->next = head->next;
node->prev = head;
head->next->prev = node;
head->next = node;
}
void removeNode(LRUNode* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToHead(LRUNode* node)
{
removeNode(node);
addToHead(node);
}
LRUNode* removeTail()
{
LRUNode* node = tail->prev;
removeNode(node);
return node;
}
public:
LRUCache(int capacity)
{
this->capacity = capacity;
head = new LRUNode(-1, -1);
tail = new LRUNode(-1, -1);
head->next = tail;
tail->prev = head;
}
int get(int key)
{
if (cache.find(key) == cache.end())
{
return -1;
}
LRUNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value)
{
if (cache.find(key) != cache.end())
{
LRUNode* node = cache[key];
node->value = value;
moveToHead(node);
}
else
{
LRUNode* newNode = new LRUNode(key, value);
cache[key] = newNode;
addToHead(newNode);
if (cache.size() > capacity)
{
LRUNode* tailNode = removeTail();
cache.erase(tailNode->key);
delete tailNode;
}
}
}
};
// 使用示例
int main()
{
LRUCache cache(2);
cache.put(1, 1);
cache.put(2, 2);
cout << "get(1): " << cache.get(1) << endl; // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cout << "get(2): " << cache.get(2) << endl; // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cout << "get(1): " << cache.get(1) << endl; // 返回 -1 (未找到)
cout << "get(3): " << cache.get(3) << endl; // 返回 3
cout << "get(4): " << cache.get(4) << endl; // 返回 4
return 0;
}
17.2.2 面试后的反思与提升
每次面试后都应该进行系统性的反思:
技术层面的反思:
- 哪些问题回答得不够完善?
- 是否存在知识盲区需要补充?
- 编码过程中出现了哪些错误?
沟通表达的反思:
- 问题理解是否准确?
- 思路表达是否清晰?
- 是否与面试官进行了有效互动?
// 面试常见问题:二叉树相关操作
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class BinaryTreeProcessor
{
public:
// 前序遍历(递归)
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> result;
preorderHelper(root, result);
return result;
}
// 前序遍历(迭代)
vector<int> preorderIterative(TreeNode* root)
{
vector<int> result;
if (!root)
{
return result;
}
stack<TreeNode*> st;
st.push(root);
while (!st.empty())
{
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->right)
{
st.push(node->right);
}
if (node->left)
{
st.push(node->left);
}
}
return result;
}
// 层次遍历
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> result;
if (!root)
{
return result;
}
queue<TreeNode*> q;
q.push(root);
while (!q.empty())
{
int levelSize = q.size();
vector<int> currentLevel;
for (int i = 0; i < levelSize; i++)
{
TreeNode* node = q.front();
q.pop();
currentLevel.push_back(node->val);
if (node->left)
{
q.push(node->left);
}
if (node->right)
{
q.push(node->right);
}
}
result.push_back(currentLevel);
}
return result;
}
// 判断是否为二叉搜索树
bool isValidBST(TreeNode* root)
{
return isValidBSTHelper(root, nullptr, nullptr);
}
private:
void preorderHelper(TreeNode* node, vector<int>& result)
{
if (!node)
{
return;
}
result.push_back(node->val);
preorderHelper(node->left, result);
preorderHelper(node->right, result);
}
bool isValidBSTHelper(TreeNode* node, TreeNode* minNode, TreeNode* maxNode)
{
if (!node)
{
return true;
}
if ((minNode && node->val <= minNode->val) ||
(maxNode && node->val >= maxNode->val))
{
return false;
}
return isValidBSTHelper(node->left, minNode, node) &&
isValidBSTHelper(node->right, node, maxNode);
}
};
// 构建测试二叉树
TreeNode* buildTestTree()
{
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
return root;
}
int main()
{
BinaryTreeProcessor processor;
TreeNode* root = buildTestTree();
cout << "前序遍历(递归): ";
vector<int> preorder = processor.preorderTraversal(root);
for (int val : preorder)
{
cout << val << " ";
}
cout << endl;
cout << "前序遍历(迭代): ";
vector<int> preorderIter = processor.preorderIterative(root);
for (int val : preorderIter)
{
cout << val << " ";
}
cout << endl;
cout << "层次遍历: " << endl;
vector<vector<int>> levels = processor.levelOrder(root);
for (size_t i = 0; i < levels.size(); i++)
{
cout << "第 " << i << " 层: ";
for (int val : levels[i])
{
cout << val << " ";
}
cout << endl;
}
// 测试二叉搜索树验证
TreeNode* bstRoot = new TreeNode(2);
bstRoot->left = new TreeNode(1);
bstRoot->right = new TreeNode(3);
cout << "是否为二叉搜索树: " << (processor.isValidBST(bstRoot) ? "是" : "否") << endl;
return 0;
}
17.3 群体面试策略与技巧
群体面试(如群面、小组讨论)考察候选人的团队协作和沟通能力:
有效参与策略:
- 提前了解面试形式和评价标准
- 平衡发言频率,既不过于沉默也不过于强势
- 展现建设性意见和团队合作精神
角色定位建议:
- 根据自身特点选择适合的角色:领导者、记录者、时间管理者等
- 关注团队目标而非个人表现
- 学会倾听和整合他人观点
通过系统的技术准备和面试技巧训练,结合实际的编码实践,候选人可以显著提升面试表现和通过率。重要的是保持持续学习的态度,从每次面试经历中吸取经验,不断完善自己的技术体系和沟通能力。
更多推荐


所有评论(0)