交换两个变量
#include <iostream>
template<typename T>
void swapWithoutTemp(T& a, T& b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
十进制vector 输出各自二进制中1个数
std::vector<int> countBitsInVector(const std::vector<int>& decimalVector)
{
std::vector<int> bitCounts;
bitCounts.reserve(decimalVector.size()); // 预分配空间以提高效率
for (int number : decimalVector)
{
// 使用std::bitset来获取二进制表示中1的个数
std::bitset<32> binaryRepresentation(number); // 假设整数是32位的
bitCounts.push_back(binaryRepresentation.count());
}
return bitCounts;
}
std::vector<int> countBitsInVector(const std::vector<int>& decimalVector)
{
std::vector<int> bitCounts;
bitCounts.reserve(decimalVector.size()); // 预分配空间以提高效率
for (int number : decimalVector)
{
int count = 0;
int n = number;
while (n)
{
count += n & 1; // 检查最低位是否为1
n >>= 1; // 右移一位
}
bitCounts.push_back(count);
}
return bitCounts;
}
拷贝字符串std::strcmp
char* copyString(const char* src)
{
// 确定原始字符串的长度
int length = 0;
while (src[length] != '\0')
{
++length;
}
// 为新字符串分配内存(包括空字符)
char* dest = new char[length + 1];
// 拷贝字符串
for (int i = 0; i < length; ++i)
{
dest[i] = src[i];
}
// 添加空字符到字符串的末尾
dest[length] = '\0';
// 返回新字符串
return dest;
}
void copyString(const char* src, char* dest, int destSize)
{
int i = 0;
while (src[i] != '\0' && i < destSize - 1)
{
dest[i] = src[i];
++i;
}
dest[i] = '\0'; // 确保目标字符串以空字符结尾
}
逆转字符串
void reverseString(char* str)
{
if (str == nullptr)
return; // 检查空指针
char* start = str; // 指向字符串开始
char* end = str; // 初始也指向字符串开始,然后移动到字符串末尾
// 移动end指针到字符串末尾的前一个字符
while (*end != '\0')
{
end++;
}
end--; // 回退一步,因为end当前指向的是字符串末尾的空字符
// 逆转字符串
while (start < end)
{
// 交换start和end指向的字符
char temp = *start;
*start = *end;
*end = temp;
// 向中间移动指针
start++;
end--;
}
}
topk
std::vector<int> findTopK(const std::vector<int>& nums, int k)
{
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; // 小顶堆
for (int num : nums)
{
if (minHeap.size() < k)
{
minHeap.push(num);
} else if (num > minHeap.top())
{
minHeap.pop();
minHeap.push(num);
}
}
std::vector<int> topK;
while (!minHeap.empty())
{
topK.push_back(minHeap.top());
minHeap.pop();
}
std::reverse(topK.begin(), topK.end()); // 因为我们从小顶堆中取出元素是逆序的,所以需要反转
return topK;
}
std::vector<int> findTopK(const std::vector<int>& nums, int k)
{
std::multiset<int> ms; // 默认是升序排序
std::vector<int> topK;
for (int num : nums)
{
ms.insert(num);
if (ms.size() > k)
{
// 因为是升序排序,所以最小的元素在begin()位置
ms.erase(ms.begin());
}
}
// 将multiset中的元素复制到vector中
for (int num : ms)
{
topK.push_back(num);
}
// 因为multiset是升序排序,如果需要降序结果,可以在这里反转vector
std::reverse(topK.begin(), topK.end());
return topK;
}
findKthLargest
//时间复杂度是O(NlogN)
int findKthLargest(const std::vector<int>& nums, int k)
{
std::multiset<int> ms(nums.begin(), nums.end()); // 构造multiset并排序
// 由于multiset是升序排序,第k大的元素将是倒数第(k-1)个元素
auto it = ms.rbegin(); // 获取指向最后一个元素的迭代器
std::advance(it, k - 1); // 向前移动(k-1)个位置
return *it; // 返回第k大的元素
}
//O(N)
int partition(std::vector<int>& nums, int left, int right)
{
int pivot = nums[right];
int i = left - 1;
for (int j = left; j < right; ++j)
{
if (nums[j] <= pivot)
{
++i;
std::swap(nums[i], nums[j]);
}
}
std::swap(nums[i + 1], nums[right]);
return i + 1;
}
int quickSelect(std::vector<int>& nums, int k, int left, int right)
{
if (left == right)
{
return nums[left]; // 只有一个元素时直接返回
}
int pivotIndex = partition(nums, left, right);
if (k == pivotIndex)
{
return nums[k]; // 找到第k大的元素
}
else if (k < pivotIndex)
{
return quickSelect(nums, k, left, pivotIndex - 1); // 在左侧分区中查找
}
else
{
return quickSelect(nums, k, pivotIndex + 1, right); // 在右侧分区中查找
}
}
int findKthLargest(std::vector<int>& nums, int k)
{
int n = nums.size();
// 注意,我们是找第k大的元素,所以要转换成对应的索引
// 例如,第1大的元素索引是n-1,第2大的元素索引是n-2,依此类推
return quickSelect(nums, n - k, 0, n - 1);
}
std::reverse
template<class BidirectionalIterator>
void reverse(BidirectionalIterator first, BidirectionalIterator last)
{
while (first != last && first != --last)
{
std::iter_swap(first++, last);
}
}
LRU
#include <iostream>
#include <unordered_map>
#include <list>
template<typename Key, typename Value>
class LRUCache
{
private:
int capacity;
std::list<std::pair<Key, Value>> cacheList;
std::unordered_map<Key, typename std::list<std::pair<Key, Value>>::iterator> cacheMap;
public:
LRUCache(int capacity) : capacity(capacity) {}
Value get(const Key& key)
{
if (cacheMap.find(key) == cacheMap.end())
{
throw std::runtime_error("Key not found");
}
// Move the accessed item to the front of the list
cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);
return cacheMap[key]->second;
}
void put(const Key& key, const Value& value)
{
if (cacheMap.find(key) != cacheMap.end())
{
// Update existing item
cacheMap[key]->second = value;
// Move the updated item to the front of the list
cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);
}
else
{
// Insert new item
if (cacheList.size() >= capacity)
{
// Remove the least recently used item (back of the list)
auto it = cacheList.back();
cacheMap.erase(it.first);
cacheList.pop_back();
}
cacheList.emplace_front(key, value);
cacheMap[key] = cacheList.begin();
}
}
};
int main()
{
LRUCache<int, std::string> lruCache(3);
lruCache.put(1, "one");
lruCache.put(2, "two");
lruCache.put(3, "three");
std::cout << lruCache.get(1) << std::endl; // Output: one
lruCache.put(4, "four"); // Evicts key 2
try
{
std::cout << lruCache.get(2) << std::endl; // Should throw an exception
} catch (const std::runtime_error& e) {
std::cout << e.what() << std::endl; // Output: Key not found
}
std::cout << lruCache.get(3) << std::endl; // Output: three
std::cout << lruCache.get(4) << std::endl; // Output: four
return 0;
}
#include <iostream>
#include <list>
#include <unordered_map>
template <typename KeyType, typename ValueType>
class LRUCache {
private:
int capacity;
std::list<std::pair<KeyType, ValueType>> cacheList;
std::unordered_map<KeyType, typename std::list<std::pair<KeyType, ValueType>>::iterator> cacheMap;
public:
LRUCache(int capacity) : capacity(capacity) {}
void put(KeyType key, ValueType value)
{
auto it = cacheMap.find(key);
if (it != cacheMap.end())
{
// Key exists, update the value and move it to the front of the list
it->second->second = value;
cacheList.splice(cacheList.begin(), cacheList, it->second);
}
else
{
// Key does not exist, insert the new key-value pair
if (cacheList.size() == capacity)
{
// Cache is full, remove the least recently used item
auto last = cacheList.back();
cacheMap.erase(last.first);
cacheList.pop_back();
}
cacheList.emplace_front(key, value);
cacheMap[key] = cacheList.begin();
}
}
bool get(KeyType key, ValueType &value)
{
auto it = cacheMap.find(key);
if (it != cacheMap.end())
{
// Key exists, move it to the front of the list and return the value
cacheList.splice(cacheList.begin(), cacheList, it->second);
value = it->second->second;
return true;
}
return false; // Key does not exist
}
};
LRU(Least Recently Used)是一种常见的缓存替换算法,即将最近最少使用的数据进行替换。下面是一个用C++实现LRU缓存的面试题示例:
#include <iostream>
#include <list>
#include <unordered_map>
class LRUCache {
public:
LRUCache(int capacity) : _capacity(capacity) {}
int get(int key) {
auto item = cacheMap.find(key);
if (item == cacheMap.end()) {
return -1;
} else {
// 使用 splice 将元素移到 list 的前面,表示最近使用
cacheList.splice(cacheList.begin(), cacheList, item->second);
return item->second->second; // 使用 iterator 访问 pair 的 value
}
}
void put(int key, int value) {
auto item = cacheMap.find(key);
if (item != cacheMap.end()) {
// 更新现有元素的值,并将其移到 list 的前面
item->second->second = value;
cacheList.splice(cacheList.begin(), cacheList, item->second);
} else {
if (cacheList.size() == _capacity) {
// 删除最久未使用的元素(list 的末尾)
int delKey = cacheList.back().first;
cacheList.pop_back();
cacheMap.erase(delKey);
}
// 插入新元素到 list 的前面,并更新 map
cacheList.emplace_front(key, value);
cacheMap[key] = cacheList.begin();
}
}
private:
int _capacity;
std::list<std::pair<int, int>> cacheList;
std::unordered_map<int, std::list<std::pair<int, int>>::iterator> cacheMap;
};
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
#include <iostream>
#include <unordered_map>
#include <list>
#include <stdexcept>
template<typename K, typename V>
class LRUCache {
private:
int capacity;
std::list<std::pair<K, V>> cacheList;
std::unordered_map<K, typename std::list<std::pair<K, V>>::iterator> cacheMap;
public:
LRUCache(int capacity) : capacity(capacity) {}
V get(const K& key) {
auto it = cacheMap.find(key);
if (it == cacheMap.end()) {
throw std::runtime_error("Key not found");
}
cacheList.splice(cacheList.begin(), cacheList, it->second); // Move to front
return it->second->second;
}
void put(const K& key, const V& value) {
auto it = cacheMap.find(key);
if (it != cacheMap.end()) {
cacheList.erase(it->second); // Remove old entry
}
cacheList.emplace_front(key, value); // Insert new entry at front
cacheMap[key] = cacheList.begin(); // Update map
if (cacheList.size() > capacity) {
auto last = cacheList.end();
--last; // Go to the last element
cacheMap.erase(last->first); // Remove from map
cacheList.pop_back(); // Remove from list
}
}
};
int main() {
LRUCache<int, int> lruCache(2);
lruCache.put(1, 1);
lruCache.put(2, 2);
std::cout << lruCache.get(1) << std::endl; // 1
lruCache.put(3, 3); // Evicts key 2
try {
std::cout << lruCache.get(2) << std::endl; // Throws an exception
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
}
lruCache.put(4, 4); // Evicts key 1
std::cout << lruCache.get(1) << std::endl; // Throws an exception
std::cout << lruCache.get(3) << std::endl; // 3
std::cout << lruCache.get(4) << std::endl; // 4
return 0;
}
mutex互斥锁
#include <atomic>
#include <thread>
#include <iostream>
#include <chrono>
#include <this_thread>
class Mutex {
private:
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock()
{
while (flag.test_and_set(std::memory_order_acquire))
{
// 忙等待(自旋锁)
}
}
void unlock() {
flag.clear(std::memory_order_release);
}
};
单例模式,线程安全版本
#include <memory>
#include <mutex>
class Singleton {
private:
static std::shared_ptr<Singleton> instance_;
static std::once_flag onceFlag_;
Singleton() {} // 私有构造函数,防止外部创建实例
Singleton(const Singleton&) = delete; // 禁止拷贝构造
Singleton& operator=(const Singleton&) = delete; // 禁止拷贝赋值
public:
static std::shared_ptr<Singleton> getInstance() {
std::call_once(onceFlag_, []() {
instance_ = std::shared_ptr<Singleton>(new Singleton());
});
return instance_;
}
// 其他成员函数...
};
// 初始化静态成员变量
std::shared_ptr<Singleton> Singleton::instance_ = nullptr;
std::once_flag Singleton::onceFlag_;
翻转链表
class Solution {
public:
// 定义:输入一个单链表头结点,将该链表反转,返回新的头结点
ListNode* reverse(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode* last = reverse(head->next);
head->next->next = head;
head->next = nullptr;
return last;
}
};
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr) {
ListNode* nextTemp = curr->next; // 保存下一个节点
curr->next = prev; // 翻转当前节点的指针
prev = curr; // 将当前节点设为前一个节点
curr = nextTemp; // 移动到下一个节点
}
return prev; // 当原链表遍历完后,prev就变成了新的头结点
}
void printList(ListNode* head) {
ListNode* curr = head;
while (curr != nullptr) {
std::cout << curr->val << " ";
curr = curr->next;
}
std::cout << std::endl;
}
四则运算
#include <iostream>
#include <stack>
#include <string>
#include <sstream>
#include <cctype>
int precedence(char op) {
switch (op) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
int applyOp(int a, int b, char op) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/':
if (b != 0) return a / b;
else {
std::cerr << "Error: Division by zero!" << std::endl;
exit(EXIT_FAILURE);
}
default: return 0;
}
}
int evaluate(const std::string &expression) {
std::stack<int> values;
std::stack<char> ops;
for (size_t i = 0; i < expression.length(); ++i) {
if (expression[i] == ' ') continue;
else if (isdigit(expression[i])) {
int val = 0;
while (i < expression.length() && isdigit(expression[i])) {
val = (val * 10) + (expression[i] - '0');
i++;
}
values.push(val);
i--; // 因为for循环还会自增,所以这里需要减一
}
else if (expression[i] == '(') {
ops.push(expression[i]);
}
else if (expression[i] == ')') {
while (!ops.empty() && ops.top() != '(') {
int val2 = values.top(); values.pop();
int val1 = values.top(); values.pop();
char op = ops.top(); ops.pop();
values.push(applyOp(val1, val2, op));
}
if (!ops.empty()) ops.pop(); // 弹出'('
}
else {
while (!ops.empty() && precedence(ops.top()) >= precedence(expression[i])) {
int val2 = values.top(); values.pop();
int val1 = values.top(); values.pop();
char op = ops.top(); ops.pop();
values.push(applyOp(val1, val2, op));
}
ops.push(expression[i]);
}
}
while (!ops.empty()) {
int val2 = values.top(); values.pop();
int val1 = values.top(); values.pop();
char op = ops.top(); ops.pop();
values.push(applyOp(val1, val2, op));
}
return values.top();
}
高并发消息队列
在C++中实现一个高并发的消息队列需要考虑线程安全、性能以及可扩展性。以下是一个简化的高并发消息队列的实现示例,它使用了互斥锁(
std::mutex)和条件变量(std::condition_variable)来确保线程安全和同步。
#include <queue>
#include <mutex>
#include <condition_variable>
#include <optional>
template <typename T>
class ConcurrentQueue {
private:
std::queue<T> queue_;
std::mutex mutex_;
std::condition_variable cond_var_;
public:
void push(const T& item) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(item);
cond_var_.notify_one(); // 通知等待的线程
}
std::optional<T> pop() {
std::unique_lock<std::mutex> lock(mutex_);
cond_var_.wait(lock, [this]{ return !queue_.empty(); }); // 等待队列非空
T item = queue_.front();
queue_.pop();
return item;
}
bool empty() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty();
}
};
这个
ConcurrentQueue类模板提供了一个线程安全的队列,可以在多个线程之间共享。push方法用于向队列中添加元素,而pop方法用于从队列中取出元素。如果队列为空,pop方法会阻塞调用线程,直到队列中有元素可用。这里有几个关键点需要注意:
- 互斥锁(
**std::mutex**):用于保护队列数据结构的访问,确保在同一时间只有一个线程可以修改队列。- 条件变量(
**std::condition_variable**):用于在队列为空时阻塞pop方法的调用线程,并在有元素被push到队列时唤醒这些线程。**std::optional<T>**:用于表示pop方法可能返回一个值,也可能在队列为空时返回空值。这里使用std::optional来优雅地处理这种情况,而不是返回一个特殊值或抛出异常。**std::lock_guard**和**std::unique_lock**:这些RAII(Resource Acquisition Is Initialization)包装器用于自动管理锁的生命周期,确保在离开作用域时自动释放锁。请注意,这个实现是一个基本的示例,可能需要根据具体的应用场景进行调整和优化。例如,在高负载下,这个简单的实现可能会成为性能瓶颈。在实际应用中,你可能需要考虑使用更高效的并发数据结构,如无锁队列,或者使用多个队列和工作者线程来分散负载。此外,对于更复杂的多线程环境,你还可能需要考虑如何处理线程的创建、管理和销毁,以及如何处理线程的同步和通信问题。
二叉树序列化反序列化
vector xx ={0 1 2 nullptr nullptr 4 5}
序列化
对于序列化,我们可以使用层序遍历(广度优先搜索,BFS)来遍历二叉树,并将每个节点的值(或表示空节点的特殊值)添加到vector<string>中。
#include <vector>
#include <string>
#include <queue>
#include <sstream>
using namespace std;
// 假设二叉树节点的定义如下
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
vector<string> serialize(TreeNode* root) {
vector<string> result;
if (!root) return result; // 如果树为空,则返回空vector
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
if (node) {
// 将节点值转换为字符串并添加到结果中
ostringstream oss;
oss << node->val;
result.push_back(oss.str());
q.push(node->left); // 将左子节点加入队列
q.push(node->right); // 将右子节点加入队列
} else {
// 使用空字符串表示空节点
result.push_back("null");
}
}
return result;
}
反序列化
对于反序列化,我们同样可以使用队列来进行层序遍历的重建过程。
TreeNode* deserialize(vector<string>& data) {
if (data.empty()) return nullptr; // 如果数据为空,则返回空树
TreeNode* root = new TreeNode(stoi(data[0])); // 创建根节点
queue<TreeNode*> q;
q.push(root);
int i = 1; // 从第二个元素开始处理,因为第一个元素已经是根节点了
while (i < data.size()) {
TreeNode* node = q.front();
q.pop();
if (data[i] != "null") { // 如果不是空节点
node->left = new TreeNode(stoi(data[i])); // 创建左子节点
q.push(node->left); // 将左子节点加入队列以便后续处理其子节点
}
i++;
if (i < data.size() && data[i] != "null") { // 如果不是空节点且未越界
node->right = new TreeNode(stoi(data[i])); // 创建右子节点
q.push(node->right); // 将右子节点加入队列以便后续处理其子节点
}
i++;
}
return root;
}
首先,我们定义一个简单的二叉树节点结构:
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
序列化
对于序列化,我们可以使用前序遍历(根-左-右)。当遇到nullptr时,我们将其表示为特殊字符串(例如"null")。
#include <vector>
#include <string>
#include <sstream>
std::vector<std::string> serialize(TreeNode* root) {
std::vector<std::string> result;
serializeHelper(root, result);
return result;
}
void serializeHelper(TreeNode* node, std::vector<std::string>& result) {
if (node == nullptr) {
result.push_back("null");
return;
}
std::stringstream ss;
ss << node->val;
result.push_back(ss.str());
serializeHelper(node->left, result);
serializeHelper(node->right, result);
}
反序列化
对于反序列化,我们同样使用前序遍历来重建树。
TreeNode* deserialize(const std::vector<std::string>& data, int& index) {
if (index >= data.size()) return nullptr;
if (data[index] == "null") {
index++;
return nullptr;
}
TreeNode* node = new TreeNode(std::stoi(data[index++]));
node->left = deserialize(data, index);
node->right = deserialize(data, index);
return node;
}
TreeNode* deserialize(const std::vector<std::string>& data) {
int index = 0;
return deserialize(data, index);
}
atoi、std::to_string 函数
isdigit
bool isdigint(char c)
{
return (c >= '0' && c <= '9');
}
atoi函数
int myAtoi(const char* str) {
int result = 0;
int sign = 1;
int i = 0;
// 处理空格
while (str[i] == ' ') {
i++;
}
// 处理正负号
if (str[i] == '-' || str[i] == '+') {
sign = (str[i] == '-') ? -1 : 1;
i++;
}
// 转换数字
while (str[i] >= '0' && str[i] <= '9') {
if (result > INT_MAX / 10 || (result == INT_MAX / 10 && str[i] - '0' > INT_MAX % 10)) {
return (sign == 1) ? INT_MAX : INT_MIN;
}
result = result * 10 + (str[i] - '0');
i++;
}
return result * sign;
}
std::to_string
std::string myToString(int num) {
if (num == 0) {
return "0";
}
std::string result = "";
bool isNegative = false;
if (num < 0) {
isNegative = true;
num = -num;
}
while (num > 0) {
char digit = '0' + (num % 10);
result = digit + result;
num /= 10;
}
if (isNegative) {
result = '-' + result;
}
return result;
}
无序链表排序
#include <iostream>
// 链表节点
struct Node {
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
// 插入节点并保持链表有序
void insertSorted(Node*& head, int val) {
Node* newNode = new Node(val);
if (head == nullptr || val < head->data) {
newNode->next = head;
head = newNode;
} else {
Node* current = head;
while (current->next != nullptr && val > current->next->data) {
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}
// 对链表进行排序
void sortLinkedList(Node*& head) {
Node* sortedList = nullptr;
Node* current = head;
while (current != nullptr) {
Node* next = current->next;
insertSorted(sortedList, current->data);
current = next;
}
head = sortedList;
}
// 打印链表
void printList(Node* head) {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
}
快排
#include <iostream>
// 链表节点
struct Node {
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
// 将链表分成两部分,小于基准值的放在左边,大于等于基准值的放在右边
Node* partition(Node* head, Node* end, Node** newHead, Node** newEnd) {
Node* pivot = end;
Node* prev = nullptr;
Node* current = head;
Node* tail = pivot;
while (current != pivot) {
if (current->data < pivot->data) {
if (*newHead == nullptr) {
*newHead = current;
}
prev = current;
current = current->next;
} else {
if (prev) {
prev->next = current->next;
}
Node* temp = current->next;
current->next = nullptr;
tail->next = current;
tail = current;
current = temp;
}
}
if (*newHead == nullptr) {
*newHead = pivot;
}
*newEnd = tail;
return pivot;
}
// 使用快速排序对链表进行排序
Node* quickSort(Node* head, Node* end) {
if (head == nullptr || head == end) {
return head;
}
Node* newHead = nullptr;
Node* newEnd = nullptr;
Node* pivot = partition(head, end, &newHead, &newEnd);
if (newHead != pivot) {
Node* temp = newHead;
while (temp->next != pivot) {
temp = temp->next;
}
temp->next = nullptr;
newHead = quickSort(newHead, temp);
temp = newHead;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = pivot;
}
pivot->next = quickSort(pivot->next, newEnd);
return newHead;
}
相交链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
// p1 指向 A 链表头结点,p2 指向 B 链表头结点
ListNode *p1 = headA, *p2 = headB;
while (p1 != p2) {
// p1 走一步,如果走到 A 链表末尾,转到 B 链表
if (p1 == nullptr) {
p1 = headB;
} else {
p1 = p1->next;
}
// p2 走一步,如果走到 B 链表末尾,转到 A 链表
if (p2 == nullptr) {
p2 = headA;
} else {
p2 = p2->next;
}
}
return p1;
}
};
找出一个字符串中最长不重复字串的长度
时间复杂度O(n)
int longestUniqueSubstr(const std::string& str) {
int n = str.size();
int maxLength = 0; // 存储最长不重复子串的长度
int left = 0, right = 0; // 滑动窗口的左右指针
std::unordered_set<char> charSet; // 用于存储窗口中的字符
while (right < n) {
// 如果当前字符不在窗口中,则将其添加到窗口中,并尝试扩大窗口
if (charSet.find(str[right]) == charSet.end()) {
charSet.insert(str[right++]);
maxLength = std::max(maxLength, right - left);
} else { // 如果当前字符已经在窗口中,则缩小窗口直到该字符不再在窗口中
charSet.erase(str[left++]);
}
}
return maxLength;
}
斐波那契
递归实现 (fibonacciRecursive):
int fibonacciRecursive(int n) {
if (n <= 1) {
return n;
}
return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
}
- 时间复杂度: O(2^n)。这是因为对于每个
fibonacciRecursive(n)调用,它会产生两个子调用fibonacciRecursive(n-1)和fibonacciRecursive(n-2),这导致了一个二叉树的递归结构,其深度为n,因此总的调用次数大致为2^n。- 空间复杂度: O(n)。这是由于递归栈的深度,它随着n的增加而增加。
动态规划实现 (fibonacciDynamic):
int fibonacciDynamic(int n) {
if (n <= 1) {
return n;
}
std::vector<int> dp(n + 1);
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
- 时间复杂度: O(n)。这是因为我们只遍历了数列一次,计算了每个位置的值。
- 空间复杂度: O(n)。这是因为我们使用了一个大小为n+1的数组来存储中间结果。虽然我们可以优化到只使用几个变量来存储前两个斐波那契数,从而将空间复杂度降低到O(1),但在上述实现中,我们保持了O(n)的空间复杂度以展示基本的动态规划思想。
// 使用动态规划实现斐波那契数列,并优化空间复杂度
int fibonacciOptimized(int n) {
if (n <= 1) {
return n;
}
int prev = 0; // 前一个斐波那契数
int curr = 1; // 当前斐波那契数
int next; // 下一个斐波那契数
for (int i = 2; i <= n; ++i) {
next = prev + curr; // 计算下一个斐波那契数
prev = curr; // 更新前一个斐波那契数
curr = next; // 更新当前斐波那契数
}
return curr; // 返回第n个斐波那契数
}
在这个实现中,我们只使用了三个整数变量:
prev、curr和next。在每次迭代中,我们计算下一个斐波那契数,并更新prev和curr的值。这样,我们就不需要存储整个数列,从而显著减少了空间使用。这种方法的时间复杂度仍然是O(n),但空间复杂度已经降低到O(1)。
二叉树和最大的层
为了找到二叉树中和最大的层,我们首先需要定义二叉树的结构,并编写一个函数来遍历二叉树的每一层,同时计算每一层的节点和,最后找到和最大的层。
以下是一个简单的C++实现,其中包括了二叉树的定义、层序遍历(使用队列)以及寻找和最大的层的函数。
#include <iostream>
#include <queue>
#include <vector>
#include <climits>
using namespace std;
// 定义二叉树节点
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 找到二叉树中和最大的层
int maxLevelSum(TreeNode* root)
{
if (!root) return 0; // 如果树为空,则返回0(或适当处理)
queue<TreeNode*> q;
q.push(root);
int maxSum = INT_MIN; // 初始化为最小整数
int maxLevel = 0; // 记录最大和的层数
int level = 0; // 当前遍历的层数
while (!q.empty())
{
int size = q.size();
int sum = 0;
// 遍历当前层的所有节点
for (int i = 0; i < size; ++i)
{
TreeNode* node = q.front();
q.pop();
sum += node->val; // 累加当前层节点的值
// 将当前节点的左右子节点加入队列(如果存在)
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
// 更新最大和及对应的层数
if (sum > maxSum)
{
maxSum = sum;
maxLevel = level;
}
level++; // 进入下一层
}
return maxLevel;
}
// 测试代码
int main() {
// 构建一个测试用的二叉树
// 1
// / \
// 2 3
// / \
// 4 5
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);
cout << "The level with maximum sum is: " << maxLevelSum(root) << endl;
// 清理内存
// 注意:在实际使用中,应编写适当的函数来递归删除树中的所有节点以避免内存泄漏
return 0;
}
这个实现中,我们首先定义了一个
TreeNode结构来代表二叉树的节点。maxLevelSum函数使用了层序遍历(通过队列)来遍历二叉树的每一层,同时计算每一层的节点和。在遍历过程中,我们记录并更新和最大的层及其对应的和。最后,函数返回和最大的层数。请注意,在实际应用中,当二叉树不再需要时,应适当删除树中的所有节点以避免内存泄漏。这里为了简化,我们没有包含删除节点的代码。