diff --git a/Campus_interview/ATTENTION.cc b/Campus_interview/ATTENTION.cc new file mode 100644 index 0000000..bb0d716 --- /dev/null +++ b/Campus_interview/ATTENTION.cc @@ -0,0 +1,859 @@ + +/* + 附:strcpy和memcpy的区别是什么? + 答:1.复制的内容不同;strcpy只能复制字符串,而memcpy可以复制任何内容,例如字符数组、整形、结构体、类等 + 2.复制的方法不同;strcpy不需要指定长度,它遇到被复制的字符的串结束符'\0'才结束,所以容易溢出;而memcpy则是根据第3个参数(字节数)来决定复制的长度 + 3.用途不同;通常在复制字符串时使用strcpy,而需要复制一些其他类型数据时则一般使用memcpy + + 附:使用memcpy需要注意些什么? + 答:memcpy函数原型为 void *memcpy(void *dest, void *src, size_t n); memcpy用来拷贝src所指的前n个字节到dest所指的地址上 + 1.如果赋值的字节数超过了dest的空间容量,或者n超出了src的容量,这个函数是不会进行判断的,这样就会很危险;需要程序员自己检查是否有溢出的情况 + 2.注意内存重叠,即dest和src指向的数组是否具有相同的空间 +*/ + +/* + 实现memcpy函数 + 注:下面转成char*这种类型是一个一个字节拷贝,可以提前对size的值进行计算,如果是4的倍数,直接转成int型来进行拷贝,这样可以加快效率 +*/ + +void* memcpy(void *des, const void *src, size_t size) +{ + char *pDes = NULL, *pSrc = NULL; + + //泛型指针不能执行加减操作,但是可以比较大小,不能对void指针进行算法操作,所以这里需要转换成char* + //如果存在内存重叠则从后往前进行赋值 + if(src < des && (char*)src + size > (char*)des) + { + pDes = (char*)des + size - 1; //char类型的所占的字节数恰好为1 + pSrc = (char*)src + size - 1; + while(size--) { + *pDes-- = *pSrc--; + } + } + else + { + //不存在内存重叠就从前往后赋值 + pDes = (char*)des; + pSrc = (char*)src; + while(size--) { + *pDes++ = *pSrc++; + } + } + + return des; +} + + +/* + strcpy函数的实现 (会将结尾的'\0'也复制过去) +*/ + +void strcpy(char *des, char *src) +{ + if(des == nullptr || src == nullptr) return; + + char *pDes = des, *pSrc = src; + + while((*pDes++ = *pSrc++) != '\0'); + +} + + +/* + 实现strcmp函数 +*/ + +// 注意:这里函数参数是一个char类型,但是下面比较的时候必须转化成unsigned char类型 +// char类型的数值范围为 -128~127, 无符号字符值的范围为 0~255, 而字符串的ASCII没有负值 +// 比如某个字符ASCII为1, 某个字符ASCII为 = 255, 作为无符号数相减会得到-254,结果正确; 但是作为有符号数相减会得到2,结果错误 + +int strcmp(const char *str1, const char *str2) +{ + int res = 0; + + while(!(res = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1 && *str2) { + str1++; + str2++; + } + + if(res > 0) return 1; + else if(res < 0) return -1; + + return 0; +} + + + +/* + string类的实现 + +*/ + +class String +{ +private: + char *str; //指向字符串的指针 + size_t len; //字符串中的的实际字符长度(不包含结尾的'\0') + +public: + String(const char *s = NULL) //这里给出了默认值就可以实现空对象, 如 String str; + { + if(s == NULL) { + str = new char[1]; + *str = '\0'; + len = 0; + } + else { + len = strlen(s); + str = new char[len + 1]; + strcpy(str, s); //字符串复制函数(会将结尾符一起复制) + } + } + + //拷贝构造(深拷贝) + String(const String &demo) + { + len = demo.len; + str = new char[len + 1]; + strcpy(str, demo.str); + } + + //注意:以后一切赋值运算符全部返回引用,防止产生临时对象调用拷贝构造 + String& operator=(const String &demo) + { + //检查自赋值,这里是拿地址比较,因为对象的地址是唯一的,而值可能相同 + if(this == &demo) return *this; + + delete[] str; + + len = demo.len; + str = new char[len + 1]; + strcpy(str, demo.str); + + return *this; //返回本对象的引用 + } + + //'+'运算符返回一个新的对象,但是原来的对象不能析构掉 + //由于返回的是临时对象,临时量在函数调用结束后就被析构了,所以只能使用值返回,不能使用引用返回 + String operator+(const String &demo) const + { + int len = strlen(str) + strlen(demo.str) + 1; + char *sp = new char[len]; + strcpy(sp, str); + strcat(sp, demo.str); //strcat(char *des, const char *src)表示将src所指向的内存中的字符连接到des所指向的内存空间后面 + String tmp(sp); + return tmp; + } + + ~String() { + delete[] str; + } + + void print() { + std::cout << str << std::endl; + } + +}; + + + + +/* + 智能指针shared_ptr的实现 + //参看CSDN博客C++分栏 +*/ + +//注意:shared_ptr未定义下标操作([]),并且不支持对指针的算术运算(++,--) + +template +class shared_ptr +{ +private: + T *ptr; //实际地址 + int *count; //存放引用计数的地址(这里必须要用地址,因为可能存在多个变量对其更改,使用地址可以多个变量都可以访问) + +public: + shared_ptr(T *pointer = nullptr) + { + ptr = pointer; + + if(ptr == nullptr) { + count = new int(0); + } + else { + count = new int(1); + } + } + + shared_ptr(const shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + count = smartPtr.count; // 多个指针变量指向同一块地址 + + //从这里可以看出,如果不使用指针更改引用计数,那么更改不了之前的智能指针的引用计数 + (*count)++; + } + + shared_ptr& operator=(const shared_ptr &smartPtr) + { + //检查自赋值 + if(ptr != smartPtr.ptr) + { + //需要先减去原来的指针的引用计数,如果引用计数为0,则需要释放原来的内存再进行赋值 + //但是如果指针原来指向为空,则引用计数为0,不能再减了 + if(ptr != nullptr && --(*count) == 0) { + delete ptr; + delete count; + } + + ptr = smartPtr.ptr; //这里只是释放掉ptr指向的内存,ptr指针仍然可以指向某个地址 + count = smartPtr.count; + (*count)++; + } + + return *this; + } + + //取指针指向的值(返回的是引用) + T& operator*() { return *ptr; } + + //注意:->操作符返回的是地址; p->fun(); 等价于 (*p).fun(); + //使用指针直接->指向函数地址,p需要是一个指针 + T* operator->() { return ptr; } + + //只能指针只有当引用计数等于0时才释放指向的内存 + ~shared_ptr() + { + //为空则说明该智能指针没有直接指向任何对象,只释放count的内存即可 + if(ptr == nullptr) { + delete count; + } + else if(--(*count) == 0) { + delete ptr; + delete count; + } + + } + + //返回引用计数 + int use_count() { return *count; } + +}; + + +//实现weak_ptr + +template +class weak_ptr +{ +public: + friend class shared_ptr; //方便shard_ptr的赋值 + T *ptr; + int *count; + + weak_ptr() { + ptr = nullptr; + count = nullptr; + } + + weak_ptr(shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + } +}; + + + +/* + weak_ptr的使用 +*/ + +#include +#include +#include + +struct Node { + int data; + std::weak_ptr next; //此处如果定义成shared_ptr会导致析构函数不能执行导致内存泄露 + + Node(int n) : data(n) {} + + ~Node() { + std::cout << "~Node() called" << std::endl; + } + +}; + +int main() { + // std::shared_ptr p1(new Node(1)); + // std::shared_ptr p2(new Node(2)); + + // std::shared_ptr p1 = std::make_shared(1); 此处也可以用make_shared模板函数 + // 推荐使用make_shared + std::shared_ptr p1 = std::make_shared(1); + std::shared_ptr p2 = std::make_shared(2); + + p1->next = p2; + p2->next = p1; + + return 0; +} + + + +/* + 怎么判断系统是大端存储还是小端存储 + //使用联合体 + + 大端存储好处: 接受数据的程序可以优先得到数据的最高位,以便快速反应(比如网络协议的应用) + 小端存储好处: 小端计算精度便于确认,因为是先读取的字节序的低位,数组的第0位固定是最低位,而大端存储下如果精度可变,很难判断数组第0位代表多大(因为先读取的是高位,舍入的话不好取舍) + 由于CPU本身是小端存储,如果内存和文件也采用小端排序的话,就可以把文件中的数据直接存储到内存中,再直接把内存中的数据存储到CPU的寄存器,这样能提高CPU读取效率 + 而且小端序比较符合人的思维 +*/ + + + +int JudgeSystem() +{ + union Test { + int num; + char ch; + }; + + union Test test; + test.num = 1; + + return test.ch; +} + + + + + + +/* + 怎么定义自己的比较函数 +*/ + +#include +#include +#include + + +//第一种方式:这种方法只能用于结构体中,就是我们排序的对象必须要是结构体才可以 +//重载比较运算符"<" + +struct Edge { + int from, to, weight; + Edge(int m_from, int m_to, int m_weight) : from(m_from), to(m_to), weight(m_weight) {} + + //1.放在结构体内部实现 //括号里面的const表示不允许修改比较的对象,这里传引用避免了对实参的拷贝 + bool operator< (const Edge &other) const { //注意:这个const必须要有,表示不修改类的成员变量,如果在函数里修改了会报错 + return weight > other.weight; + } + + //2.使用友元函数实现 + friend bool operator<(const Edge &a, const Edge &b) { + return a.weight > b.weight; + } + +}; + +//3.结构体外面实现 +// 使用大于号实现小于号,代表排序顺序与默认的顺序相反 +bool operator< (Edge a, Edge b) { + return a.weight > b.weight; +} + +int main() { + std::priority_queue que; + que.push(Edge(0,1,7)); + que.push(Edge(1,2,4)); + que.push(Edge(2,3,10)); + que.push(Edge(3,4,5)); + + while(!que.empty()) + { + std::cout << (que.top().weight) << std::endl; + que.pop(); + } + + return 0; +} + + + +//第二种方式(用的最多) +//定义一个普通的比较函数或者使用lambda表达式 + +bool cmp(std:vector a, std::vector b) { + return a[0] > b[0]; +}; + + +int main() { + std::vector> nums; + nums.push_back({2,3},{1,4},{5,6}); + + //使用定义的普通函数 + sort(nums.begin(), nums.end(), cmp); + + //使用Lambda表达式 + sort(nums.begin(), nums.end(), [](const std::vector &a, const std::vector &b) { + return a[0] > b[0]; + }) + + return 0; +} + + + +//第三种方式:operator()重载函数需要被定义在一个新的结构体内 +//重载"()" + +struct cmp { + bool operator()(const int &a, const int &b) { + return a > b; + } +}; + +int main() { + //将这个类作为模板参数传递给STL容器就可以了 + std::set mySet; + mySet.insert(3); + mySet.insert(2); + mySet.insert(1); + + for(const int &num : mySet) { + std::cout << num << " "; + } + std::cout << std::endl; + + return 0; +} + + + + +/* + 哈希表怎么删除奇数元素(关联容器怎么删除元素) +*/ + +int main() { + std::map hash; + hash.insert({1,1}); + hash.insert({2,2}); + hash.insert({3,3}); + hash.insert({4,4}); + hash.insert({5,5}); + + for(auto it = hash.begin(); it != hash.end();) + { + if(it->second&1) { + it = hash.erase(it); //erase删除it指向的元素后返回指向it后一个元素的迭代器 + } + else it++; + } + + for(auto item : hash) { + std::cout << item.first << " " << item.second << std::endl; + } + + return 0; +} + + +//附:vector怎么删除偶数元素 + +void deleteEven(std::vector &nums) +{ + for(auto it = nums.begin(); it != nums.end();) + { + if((*it)&1) { //如果是奇数 + it++; + } + else { + it = nums.erase(it); + } + } +} + + + + + +/* + 手动实现一个vector +*/ + +class MyVector +{ +private: + int *data; //实际存放元素的数组 + int capacity; //容量 + int size; //数组大小 + + void addsize(int newsize) //动态扩容函数 + { + int *newData = new int[newsize]; + for(int i = 0; i < size; i++) { + newData[i] = data[i]; + } + delete[] data; + + data = newData; + capacity = newsize; //扩容时容量增加但是size不增加,size代表的是数组元素个数 + } + +public: + MyVector() { + capacity = 1; //初始容量设置为1 + size = 0; + data = new int[capacity]; + } + + MyVector(int m_size, int val) { + data = new int[m_size]; + memset(data, val, sizeof(data)); + capacity = m_size; + size = m_size; + } + + void push_back(int val) + { + if(capacity == size) { + addsize(2*size); //两倍扩容 + } + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + int getsize() { + return size; + } + + int &operator[] (int i) { + return data[i]; + } + + ~MyVector() { + delete[] data; + } + +}; + + +//上面的扩展:实现泛型(模版vector) + +template +class MyVector +{ +private: + T *data; + int capacity, size; + + void addsize(int newsize) + { + T *newData = new T[newsize]; + for(int i = 0; i < size; i++) newData[i] = data[i]; + delete[] data; + + data = newData; + capacity = newsize; + } + +public: + MyVector() + { + capacity = 1; + size = 0; + data = new int[capacity]; + } + + MyVector(int m_size, T val = 0) + { + data = new T[m_size]; + for(int i = 0; i < m_size; i++) data[i] = val; //注意这里使用泛型就不能再使用上面的memset了,memset的第二个参数要求是int类型 + + capacity = m_size; + size = m_size; + } + + //拷贝构造 + MyVector(const MyVector &demo) + { + size = demo.size; + capacity = size; + data = new T[size]; + for(int i = 0; i < size; i++) data[i] = demo.data[i]; + } + + ~MyVector() + { + delete[] data; + } + + void push_back(int val) + { + if(size == capacity) addsize(2*size); + + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + T& operator[](int i) { + return data[i]; + } + +}; + + + + +//虚继承问题 + +class Base +{ +public: + void print() { std::cout << "Base print!" << std::endl; } + Base(){ std::cout << "Constructor" << std::endl; } +}; + +class Mid1 : virtual public Base +{ +public: + +}; + +class Mid2 : virtual public Base +{ +public: + +}; + +class Child : public Mid1, public Mid2 +{ +public: + +}; + +int main() { + Child d; + d.print(); //如果上面不加上virtual则,这里的print是无法使用的,因为存在二义性问题,Mid1继承一个base,Mid2也继承一个Base + //加上了virtual,就将共同基类设置成了虚基类,这时从不同路径继承过来的同名数据成员之在内存中只会有一个拷贝 + return 0; +} + + + +//赋值构造和移动构造问题 + +class Test +{ +public: + Test(int a) : data(new int(a)) { + std::cout << "构造函数调用" << std::endl; + } + + //拷贝构造 + Test(const Test &demo) { + std::cout << "拷贝构造调用" << std::endl; + this->data = new int(*demo.data); + } + + //移动构造,注意传参不能传入const类型,因为下面会修改 + Test(Test &&demo) { + std::cout << "移动构造调用" << std::endl; + this->data = demo.data; + demo.data = nullptr; + } + + ~Test() { + std::cout << "析构函数调用" << std::endl; + // delete data; + if(data) { + delete data; + } + } + + void print() { + if(data == nullptr) std::cout << "置为空了" << std::endl; + } + +private: + int *data; +}; + + + + +/* + 实现一个栈: 支持三个操作:top取栈顶元素,pop弹出元素,max取栈中最大元素 + 实现一个循环队列 +*/ + +class myStack +{ +private: + std::vector nums, maxVal; + int end, size, index; + +public: + myStack(int n = 0) { + nums.resize(n); + maxVal.resize(n); + end = -1; + index = -1; + size = n; + } + + bool isFull() + { + if(end == size - 1) return true; + else return false; + } + + bool isEmpty() + { + if(end == -1) return true; + else return false; + } + + int top() + { + if(isEmpty()) return -1; + return nums[end]; + } + + void push(int x) + { + if(isFull()) return; + + nums[++end] = x; + + if(index == -1 || x > maxVal[index]) maxVal[++index] = x; + else { + int tmp = maxVal[index]; + maxVal[++index] = tmp; + } + } + + int max() + { + if(isEmpty()) return -1; + return maxVal[index]; + } + + void pop() + { + if(isEmpty()) return ; + --end; + --index; + } +}; + + +class myQueue +{ +private: + int pre, tail, size; + std::vector nums; + +public: + myQueue(int n = 0) + { + nums.resize(n); + pre = tail = 0; + size = n; + } + + bool empty() + { + return pre == tail; + } + + bool full() + { + if((tail+1)%size == pre) return true; + return false; + } + + void push(int x) + { + if(full()) return; + nums[tail] = x; + tail = (tail+1)%size; + } + + void pop() + { + if(empty()) return; + + pre = (pre+1)%size; + } + + int front() + { + if(empty()) return -1; + return nums[pre]; + } + + //返回队列的长度 + int len() + { + return (tail-pre+size)%size; + } + +}; + + + +/* + 数字转汉字 + 180 -> 一百八十 + 203 -> 二百零三 + 8008 -> 八千零八 +*/ + +std::vector AA = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}; +std::vector BB = {"", "十", "百", "千", "万", "十万", "百万", "千万", "亿"}; + +std::string numberToChinese(int num) +{ + std::string res; + std::string numStr = std::to_string(num); + int k = numStr.size(); + + for(int i = 0; i < numStr.size(); i++) + { + int tmp = numStr[i] - '0'; + + if(tmp == 0) { + if(numStr[i-1] == '0' || i == numStr.size() - 1) continue; + else res += AA[tmp]; + } + else { + res += AA[tmp]; + if(numStr.size() == 2 && numStr[0] == '1' && i == 0) { + res.erase(0); //12读作十二,把1去掉 + } + res += BB[k-i-1]; + } + } + + return res; +} + +int main() { + std::cout << numberToChinese(12) << std::endl; + + return 0; +} + + diff --git a/Campus_interview/Alibaba.cc b/Campus_interview/Alibaba.cc new file mode 100644 index 0000000..397b713 --- /dev/null +++ b/Campus_interview/Alibaba.cc @@ -0,0 +1,104 @@ + + + +// 1.Leetcode第298题 : 二叉树的最长递增子序列 + +//解法一:对每个节点判断 + +int res = 0; + +std::unodered_map hash; + +int maxLenOfTree(TreeNode *root) +{ + if(root == nullptr) return 0; + + res = std::max(dfs(root), std::max(maxLenOfTree(root->left), maxLenOfTree(root->right))); + + return res; +} + +int dfs(TreeNode *root) +{ + if(root == nullptr) return 0; + + if(hash.count(root)) return hash[root]; + + int leftLen = 0, rightLen = 0; + + if(root->left && root->left->val == root->val + 1) leftLen += dfs(root->left); + if(root->right && root->right->val == root->val + 1) rightLen += dfs(root->right); + + hash[root] = 1 + std::max(leftLen, right); + + return 1 + std::max(leftLen, rightLen); +} + + +//解法二:遍历的是否记下当前节点累计递增的个数即可 + +int maxLen = 0; + +int longestConsecutive(TreeNode *root) +{ + if(root == nullptr) return 0; + + dfs(root, 1); + + return maxLen; +} + +void dfs(TreeNode *root, int len) +{ + if(root == nullptr) return ; + + maxLen = std::max(maxLen, len); + + //存在左子树 + if(root->left) + { + //左子节点比父节点大1 + if(root->left->val == root->val + 1) { + dfs(root->left, len + 1); + } + else { + dfs(root->len, 1); + } + } + else if(root->right) + { + if(root->right->val == root->val + 1) { + dfs(root->right, len + 1); + } + else { + dfs(root->right, 1); + } + } + +} + + +//解法三: 递归的时候记录最长连续序列长度 + +int maxLen = 0; + +int longestConsecutive(TreeNode *root) +{ + dfs(root, nullptr, 0); + + return maxLen; +} + +//root为pNode的父节点 +void dfs(TreeNode *pNode, TreeNode *root, int len) +{ + if(pNode == nullptr) return ; + + len = (root && pNode->val == root->val + 1) ? len + 1 : 1; + + maxLen = std::max(maxLen, len); + + dfs(pNode->left, pNode, len); + dfs(pNode->right, pNode, len); +} + diff --git a/Campus_interview/BaiDu.cc b/Campus_interview/BaiDu.cc new file mode 100644 index 0000000..8c74824 --- /dev/null +++ b/Campus_interview/BaiDu.cc @@ -0,0 +1,185 @@ + + +/* + 给一个数组,将奇数放到奇数位,偶数放到偶数位 +*/ + +void OddInOddEvenInEven(std::vector &nums) +{ + if(nums.size() <= 1) return; + + int i = 0, j = 1; + while(i < nums.size() && j < nums.size()) + { + //判断nums[i]是否为偶数,如果为偶数则向前进两位到达下一个偶数位 + while(i < nums.size() && (nums[i]%2 == 0)) { + i += 2; + } + + while(j < nums.size() && (nums[j]%2 == 1)) { + j += 2; + } + + if(i < nums.size() && j < nums.size()) { + std::swap(nums[i], nums[j]); + } + } + +} + + +/* + 给一个数组,数字内的每一个数组范围都是1~数组长度(n),求每个数字出现了多少次?返回一个合适的数据结构 +*/ +//返回数组或者map + +std::vector theFreqencyOfNums(std::vector &nums) +{ + for(int i = 0; i < n; i++) { + nums[(nums[i]-1)%n] += n; //注意:这里要取余,因为前面的数会改变掉后面的数的值 + } + + for(int i = 0; i < n; i++) { + nums[i] = (nums[i]-1)/n; + } + + return nums; //如果nums = {1,0,2,3}就表示1出现1次,2出现0次,3出现2次,4出现3次 +} + +std::vector theFreqencyOfNums(std::vector &nums) +{ + std::vector res(nums.size()); + + for(const int &n : nums) { + res[n-1]++; + } + + return res; +} + + + +/* + 计算100以内的素数和 +*/ + +int primeSum(int n) +{ + std::vector prime(n, 1); + std::vector res; + + for(int i = 2; i*i < n; i++) + { + if(prime[i]) + { + for(int j = i*i; j < n; j += i) { + if(prime[j]) { + prime[j] = 0; + res.push_back(j); + } + } + } + } + + if(!res.empty()) { + return accumulate(res.begin(), res.end(), 0); + } + + return -1; //表示n以内没有素数 +} + + +/* + 求出用{1,2,5}这三个数不同个数组合出的和为100的组合个数(184种) +*/ + +int count = 0; + +int combineCount(std::vector &nums, int target) +{ + dfs(nums, target, 0); + + return count; +} + +void dfs(std::vector &nums, int target, int pos) +{ + if(target == 0) { + count++; + return; + } + + if(target < 0) return; + + for(int i = pos; i < nums.size(); i++) { + dfs(nums, target - nums[i], i); + } + + + +/* + 实现一个bitmap +*/ + +class BitMap { +private: + std::vector vec; //这是用unsigned int来模拟,用unsigned char来模拟只需要把32改成8即可 + //不用int来模拟的原因是int是有符号数,第一个bit位会存储的符号位 +public: + BitMap(size_t size) { //size_t为无符号整形,不会存在负数.size为存储的元素总个数 + vec.resize(size/32 + 1); //每个整形可以存储32个数,当size<32时,size/32=0,因此为了保证小于32的元素个数能存储,需要加1 + } + + //设置第x bit位为1 + bool set(size_t x) + { + if(x/32 > vec.size()) { + return false; + } + + size_t index = x/32; //找到是第几个数 + size_t num = x%32; //找到是在vec[index]第几个bit位 + + vec[index] |= (1 << num); + return true; + } + + bool reset(size_t x) //将x的状态为置为0 + { + if(x/32 > vec.size()) { + return false; + } + + size_t index = x/32; + size_t num = x%32; + + vec[index] ^= (1 << num); + + return true; + } + + int find(size_t x) //查找x的状态并返回 + { + if(x/32 > vec.size()) { + return -1; + } + + size_t index = x/32; + size_t num = x%32; + + return (vec[index] >> num) & 1; + } + + + void clear() //置空该位图 + { + vec.clear(); + } +}; + + + + + + + diff --git a/Campus_interview/ByteDance.cc b/Campus_interview/ByteDance.cc new file mode 100644 index 0000000..90afbc5 --- /dev/null +++ b/Campus_interview/ByteDance.cc @@ -0,0 +1,474 @@ + +/* + 找到数组中第一个不重复的数 +*/ + +//思路:用哈希存储每个元素出现的次数即可,找到只出现一次的元素 + +int firstDistinctNum(std::vector &nums) +{ + std::unordered_map hash; + + for(const int &n : nums) { + hash[n]++; + } + + for(const int &n : nums) { + if(hash[n] == 1) return n; + } + + return -1; +} + + + +/* + 字符串翻转 "I love you"->"you love I"(相邻单词以单个空格间隔) +*/ + +void reverseStr(std::string &str) +{ + if(str.size() <= 1) return ; + + int left = 0; + + for(int right = 0; right < str.size(); right++) + { + if(str[right] == ' ') { + reverse(str.begin() + left, str.begin() + right); //注意:这里翻转的是[left, right)范围内的字符,右边是开区间 + left = right + 1; + } + } + + reverse(str.begin(), str.end()); + +} + +// 或者这样写也可以 + +void reverseWords(std::string &s) +{ + int left = 0, right = 0; + while(right < s.size()) + { + if(s[right] == ' ') { + reverse(s.begin() + left, s.begin() + right); + left = right + 1; + } + right++; + } + + //最后right = s.size() 单独拿出来 + reverse(s.begin() + left, s.begin() + right); + + reverse(s.begin(), s.end()); +} + + + +//注意:上面如果是单词之间存在多个空格,要求翻转后的单词每个间隔一个空格 +//参考Leetcode第151题 +//使用字符串流处理 + +std::string reverseWords(std:string s) +{ + std::istringstream in(s); + std::string out, res; + + while(in >> out) { + reverse(out.begin(), out.end()); + res += out + " "; + } + + res.pop_back(); + reverse(res.begin(), res.end()); + + return res; +} + + + +/* + 链表,奇数位递增,偶数位递减,从小到大排序该链表 +*/ + +//思路:1.先按奇偶位置分成两个个链表 (Leetcode第328题) +//2.将偶数位链表逆序 (Leetcode第206题) +//3.合并两个链表 (Leetcode第21题) + +ListNode *sortOddAndEvenList(ListNode *head) +{ + if(head == nullptr) return head; + + //分割两个链表 + ListNode *pOdd = head, pEven = head->next; + ListNode *pOddHead = pOdd, pEvenHead = pEven; + + while(pEven && pEven->next) { + pOdd = pOdd->next = pEven->next; + pEven = pEven->next = pOdd->next; + } + + pOdd->next = nullptr; + + //翻转偶数位链表 + pEvenHead = reverList(pEvenHead); + + //合并两个链表 + head = mergeTwoList(pOddHead, pEvenHead); + + return head; +} + +//翻转链表 +ListNode *reverList(ListNode *head) +{ + ListNode *prev = nullptr; + while(head) + { + ListNode *pNext = head->next; + head->next = prev; + prev = head; + head = pNext; + } + + return prev; +} + + +//合并两个链表(递归写法) +ListNode* mergeTwoList(ListNode *l1, ListNode *l2) +{ + if(l1 == nullptr) return l2; + else if(l2 == nullptr) return l1; + + if(l1->val < l2->val) { + l1->next = mergeTwoList(l1->next, l2); + return l1; + } + else { + l2->next = mergeTwoList(l1, l2->next); + return l2; + } + +} + +//迭代写法 +ListNode* mergeTwoList(ListNode *l1, ListNode *l2) +{ + ListNode *base = new ListNode(-1); + ListNode *node = base; + + while(l1 && l2) + { + if(l1->val < l2->val) { + node->next = l1; + l1 = l1->next; + } + else { + node->next = l2; + l2 = l2->next; + } + node = node->next; + } + + node->next = l1 ? l1 : l2; + + return base->next; +} + + +/* + 给定一条长度为L的线段,除了头和尾两个点之外,上面还有n个整数点,需要在上面再放k个新的点,使得相邻的两个点之间的最大距离最小,求这个最小的距离 +*/ + +//思路:二分 + +int main() { + int L, n, k; + std::cin >> L >> n >> k; + + std::vector nums(n + 2, 0); + nums[0] = 0; + for(int i = 1; i <= n; i++) { + std::cin >> nums[i]; + } + nums[n+1] = L; + + //最短距离为1,最大距离就为L + int left = 1, right = L; + while(left <= right) + { + int mid = left + ((right-left) >> 1); + int count = 0; //计算每个相连的点之间的长度<=mid 需要插入几个点 + for(int i = 1; i < n-2; i++) { + count += (nums[i] - nums[i-1] - 1)/mid; //注意:这里是需要再减去1,因为两点长度恰为mid不需要插入点 + } + + //要插入的点太多,则说明m太小 + if(count > k) { + left = mid + 1; + } + else if(count <= k) { //要插入的节点比要求的k小或者等于k,则尝试减小mid(减小距离) + right = mid - 1; + } + } + + std::cout << left << std::endl; + + return 0; +} + + + + +/* + 给定一个字符串,对该字符串进行删除操作,保留k个字符且相对位置不变,使得字典序最小 +*/ + +//单调栈 + +//维持一个单调递增的字符串res,遍历原来字符串,如果当前字符小于res.back()且还没删够,则弹出res末尾字符 +//如果当前字符大于res末尾字符,则直接将其加入到res中 + +std::string KeepKChar(std::string str, int k) +{ + if(k <= 0 || str.size() <= k) return str; + + k = str.size() - k; //保留k个字符就是删除n-k个字符 + + for(const char &c : str) + { + if(!res.empty() && c < res.back() && k) { + res.pop_back(); + k--; + } + + res.push_back(c); + } + + return res; +} + + + +/* + 返回所有和为k的连续子数组的下标 + //题目出的非常好 +*/ + +//hash[sum]存储的是所有和为sum的子数组的下标 +//但是如果和sum==k,这时少了从头遍历到sum的子数组 + +std::vector> subarraySum(std::vector &nums, int k) +{ + std::vector> res; + + std::unordered_map> hash; + + int sum = 0; + + std::vector index; + + for(int i = 0; i < nums.size(); i++) + { + sum += nums[i]; + int diff = sum - k; + + if(hash.count(diff)) + { + for(int n : hash[diff]) { + index.clear(); + for(int j = n + 1; j <= i; j++) { + index.push_back(j); + } + } + + res.push_back(index); + } + + if(diff == 0) { + index.clear(); + for(int j = 0; j <= i; j++) { + index.push_back(j);; + } + res.push_back(index); + } + + hash[sum].push_back(i); + } + + return res; +} + + + +/* + 有一个环上有10个点,编号从0-9,问从0点出发,每步可以顺时针到下一个点,也可以逆时针到下一个点,问经过n步到达点k有多少种方法 +*/ + +// dp[i][j]表示前i步到达j点的方法数, +// 则 dp[i][j] = dp[i-1]][(j-1+n)%n] + dp[i-1][(j+1)%n] +// base case i = 0, dp[0][0] = 1, 代表0步到达0点方法数是1 + +int GetSteps(int k) +{ + if(k <= 1) return 0; + + if(k&1) return 0; //因为一来一回需要两次,所以k为奇数则不能到达原点 + + int n = 10; //10个点 + + std::vector> dp(k+1, std::vector(n, 0)); + dp[0][0] = 1; + + for(int i = 1; i <= k; i++) { + for(int j = 0; j < n; j++) { + dp[i][j] = dp[i-1][(j-1+n)%n] + dp[i-1][(j+1)%n]; + } + } + + return dp[k][0]; +} + + + +/* + 求数组中第一个不连续的数 + 如:数组为{8,1,4,5,2,7}, 排序后为{1,2,4,5,7,8} 所以第一个不连续的数是4 +*/ + +//思路:存入有序集合中,从集合第一个元素开始递增查找,直到找到第一个不在集合中的元素 +//在集合中找到 >= 该元素的第一个元素即可 + +int firstNotSuccesiveNum(std::vector &nums) +{ + std::set mySet(nums.begin(), nums.end()); + + int x = *mySet.begin(); + + while(mySet.count(x)) { + x++; + } + + auto res = mySet.lower_bound(x); //可能数组中的数都连续 + if(res == mySet.end()) return -1; + + return *res; +} + + +/* + 有N个窗口,给定每个窗口处理一个人所需的时间,求M个人都处理完的最短时间 + 如:3个窗口,2个人, 窗口处理时间 {2,2,5}, 最终处理完最短时间是2,这两个人分别分配在前两个最小的窗口 + 如:2个窗口,3个人,窗口处理时间 {2,5}, 第一个人和第二个人放在第一个窗口,第三个人放在第2个窗口,处理时间为5 +*/ + +//思路:利用堆 +//建立一个最小堆,每到来一个人取堆顶元素加上对应窗口的处理时间重新放入到堆中 +//从第二个人开始算起,时间为堆顶元素再加上自身的值,之后再放入堆中 + +int minTimeToHandle(std::vector &time, int num) +{ + std::priority_queue, std::greater()> pq; + + for(const int &n : time) { + pq.push(time); + } + + for(int i = 1; i < num; i++) { + pq.push(pq.top()*2); + } + + return pq.top(); +} + + + +/* + Leetcode第967题 +*/ + + +std::vector res; + +std::vector numSameConsecDiff(int n, int k) +{ + for(int i = 1; i < 10; i++) { + dfs(i, 1, n, k); + } + + return res; +} + +void dfs(int prev, int pos, int n, int k) +{ + if(pos == n) { + res.push_back(prev); + return; + } + + int num = prev%10 + k; + if(num < 10) { + dfs(prev*10 + num, pos + 1, n, k); + } + + num = prev%10 - k; + if(k && num >= 0) { + dfs(prev*10 + num, pos + 1, n, k); + } + +} + + +std::vector numSameConsecDiff(int n, int k) +{ + std::vector cur = {1,2,3,4,5,6,7,8,9}; + + for(int i = 2; i <= n; i++) + { + std::vector tmp; + for(const int &x : cur) { + int y = x%10; + if(y + k < 10) { + tmp.push_back(x*10 + y+k;) + } + if(k && y - k >= 0) { + tmp.push_back(x*10 + y - k); + } + } + cur = tmp; + } + + return cur; +} + + +/* + 有n个任务,每个任务有开始和结束时间,如何安排任务的顺序,使得完成的任务个数是最多的 + 例如:(5,10), (6,9), (7,8), (9,11) +*/ + +//按照结束时间排序 + +int mostTasks(std::vector> nums) +{ + sort(nums.begin(), nums.end(), [](std::vector &a, std::vector &b){ + return a[1] < b[1]; + }); + + int count = 0; + + int end = nums[1]; + for(int i = 1; i < nums.size(); i++) { + if(end <= nums[i][0]) { + end = nums[i][1]; + count++; + } + } + + return count; +} + + + diff --git a/Campus_interview/Design_Mode.cc b/Campus_interview/Design_Mode.cc new file mode 100644 index 0000000..d450ffe --- /dev/null +++ b/Campus_interview/Design_Mode.cc @@ -0,0 +1,192 @@ + +/* + 实现单例模式 + (面试遇到一律写成返回全局对象的单例,因为返回全局对象的单例无论懒汉还是恶汉都是线程安全的) +*/ + +// 将成员函数声明成private就表示不允许外界进行访问,但是类内部成员函数和友元函数还是可以访问的 +// 为了防止类内部成员函数和友元函数访问,则将拷贝构造和和赋值运算符只给出声明,不给出实现 +// 因为单例要求有一个例子,所以构造函数需要给出实现语句 + +class Singleton +{ +private: + Singleton() {} //防止外部调用构造函数创建对象 + Singleton(const Singleton &); //阻止拷贝创建对象 (将这两个函数放在public底下使用 =delete关键字来定义成删除函数也可以) + Singleton& operator=(const Singleton &); //阻止复制运算符对对象复制 + +public: + + //懒汉式:只有调用getInstance函数才会创建对象 + static Singleton& getInstance() { //提供一个全局访问点,就需要在类中定义一个static函数,返回在类中的唯一构造的实例 + static Singleton instance; //这里的getInstace函数不能以值返回,主要是因为构造函数是私有的,外部不能创建临时对象 + return instance; //内部静态变量也是线程安全的,只会创建一个实例 + } + + void printTest() { + std::cout << "do something!" << std::endl; + } + +}; + + +//饿汉式,程序一启动对象就创建完成了,缺点是无论用于是否使用单例对象都会创建单例对象 +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + static Singleton instance; //这是错误的.static变量必须在外部实例化,而instance无法在外部调用构造函数 + +public: + static Singleton& getInstance() { + return instance; + } + + void printTest() { + std::cout << "do something!" << std::endl; + } + +}; + + +/* + 返回全局对象的懒汉式和恶汉式都是线程安全的,因为类中静态成员只会被创建一次 + 所谓线程安全就是线程执行这项操作不会带来什么危险操作(比如创建多个单例对象,段错误,内存重复释放这些错误) +*/ + +//返回指针的懒汉式单例(线程安全) +//由于懒汉式是在用于需要时才进行单例对象的创建,如果遇到多线程容易发生内存泄露,所以需要使用互斥锁 + +class Singleton +{ +private: + Singleton() { + std::cout << "我是懒汉式" << std::endl; + } + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + static Singleton *instance; + static std::mutex mut; + +public: + //返回指针的引用 + static Singleton* &getInstance() + { + //使用双检锁,好处在于只有判断指针为空的时候才加锁,避免每次调用该方法都加锁,锁的开销还是比较大的 + if(instance == nullptr) + { + std::unique_lock lock(mut); + if(instance == nullptr) { //注意这里也要判断一次,否则当两个线程同时进入时,刚开始instance都为空,第一个线程加完锁创建对象,第二个线程也会创建对象 + instance = new(std::nothrow) Singleton(); + } + } + return instance; + } + +}; + +Singleton* Singleton::instance = nullptr; +std::mutex Singleton::mut; //这个互斥锁必须初始化 + + + +//返回指针的恶汉式单例本身就是线程安全的,因为静态实例初始化之前就由主线程以单线程的方式完成了初始化,不必担心多线程问题 + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + + static Singleton* instance; + +public: + static Singleton* &getInstance() { //返回值和返回引用区别:返回值会产生一份副本,返回引用不会,但是不能返回局部对象的引用 + return instance; + } + + //释放单实例 + void deleteInstance() { + if(instance) delete instance; + instance = nullptr; + } + +}; + +Singleton* Singleton::instance = new(std::nothrow) Singleton; //虽然构造函数私有,但是全局对象初始化还是可以调用的 + + + + + + +/* + 工厂方法模式 +*/ + +class Product +{ +public: + virtual ~Product() {} + virtual std::string operation() const = 0; +}; + +class ConcreteProduct1 : public Product +{ +public: + std::string operation() const override { + return "result of ConcreteProduct1"; + } +}; + +class ConcreteProduct2 : public Product +{ +public: + std::string operation() const override { + return "result of ConcreteProduct2"; + } +}; + +class Creator +{ +public: + virtual ~Creator() {} + virtual Product* FactoryMethod() const = 0; + + std::string SomeOperation() const { + Product *product = this->FactoryMethod(); + std::string result = "Creator: The same creator's code has just worked with " + product->operation(); + + delete product; + return result; + } + +}; + +class ConcreteCreator1 : public Creator +{ +public: + Product* FactoryMethod() const override { + return new ConcreteProduct1(); + } +}; + +class ConcreteCreator2 : public Creator +{ +public: + Product* FactoryMethod() const override { + return new ConcreteProduct2(); + } + +}; + + +void clientCode(const Creator &creator) +{ + std::cout << creator.SomeOperation() << std::endl; +} + + diff --git a/Campus_interview/IPC.cc b/Campus_interview/IPC.cc new file mode 100644 index 0000000..c2118c0 --- /dev/null +++ b/Campus_interview/IPC.cc @@ -0,0 +1,435 @@ + +/* + 实现三个进程顺序打印 +*/ + + +#include +#include +#include + +std::mutex mtx; +std::condition_variable cv; +int ready = 1; + +void printString_1() +{ + std::unique_lock lk(mtx); + + int cnt = 0; + while(cnt < 10) //控制打印十次 + { + while(ready != 1) cv.wait(lk); //线程wait时会自动放弃所拥有的锁并阻塞等待; 当被唤醒时则又自动尝试申请获得原来所拥有的锁 + + std::cout << std::this_thread::get_id() << " " << "A" << std::endl; + + ready = 2; + cnt++; + cv.notify_all(); + } +} + +void printString_2() +{ + std::unique_lock lk(mtx); + + int cnt = 0; + while(cnt < 10) + { + while(ready != 2) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "B" << std::endl; + + ready = 3; + cnt++; + cv.notify_all(); + } +} + +void printString_3() +{ + std::unique_lock lk(mtx); + + int cnt = 0; + while(cnt < 10) + { + while(ready != 3) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "C" << std::endl; + + ready = 1; + cnt++; + cv.notify_all(); + } +} + +//编译的时候需要链接线程库 -lpthread +int main() { + std::thread t1(printString_1); + std::thread t2(printString_2); + std::thread t3(printString_3); + + t1.join(); + t2.join(); + t3.join(); + + return 0; +} + + +/* + 两个线程,一个线程打印数字1234,一个线程打印字母abc,要求交替打印a1b2c3d4a1b2... +*/ + + +#include +#include +#include +#include + +std::mutex mut; +std::condition_variable cv; + +int k = 0; //区分线程 + +std::string s1 = "abcd"; +std::string s2 = "1234"; + +void print1() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s1.size(); i++) + { + while(k != 0) cv.wait(lock); + std::cout << s1[i] << std::endl; //如果这里写 printf("%c", s[i]) 则会卡住 + k = 1; + + sleep(1); //打印完暂停一秒看出变化 + + cv.notify_all(); + } + } + +} + +void print2() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s2.size(); i++) + { + while(k != 1) cv.wait(lock); + std::cout << s2[i] << std::endl; + k = 0; + sleep(1); + cv.notify_all(); + } + } + +} + +int main() { + std::thread t1(print1), t2(print2); + + t1.join(); + t2.join(); + + return 0; +} + + + + + + +/* + 十个人排队使用打印机,任一时刻只能有一个人使用,用一个变量0和1两种状态分别表示这台打印机能不能使用 +*/ + + +#include +#include +#include +#include + +std::vector tv; //保存线程的状态 +std::condition_variable cv; +std::mutex mut; + +int i = 1; //打印机资源,初始化为1,表示可用 + +/* +std::condition_variable_any cv; //下面使用自动锁,则这里需要使用_any +void subi() +{ + std::lock_guard locker(mut); //使用自动锁,调用即加锁,离开作用域即解锁 + + while(i == 0) { + cv.wait(mut); //资源不可用则阻塞等待 + } + + i--; //可以使用打印机 +} + +void addi() +{ + std::lock_guard locker(mut); + + i++; //将资源变为可用 + cv.notify_all(); //通知其他阻塞的线程可以使用了 +} +*/ + +void subi() +{ + std::unique_lock lock(mut); //加锁 + + while(i == 0) { + cv.wait(lock); + } + + i--; + + cv.notify_all(); +} + +void addi() +{ + std::unique_lock lock(mut); + + i++; //对共享资源的访问一定要加锁 + + cv.notify_all(); +} + + + +void func(int j) +{ + subi(); //模拟使用打印机 + std::cout << "I am thread " << j << ", i = " << i << std::endl; + addi(); //使用完归还打印机资源 +} + + +int main() { + for(int j = 0; j < 10; j++) { + std::thread t(func, j); + tv.push_back(std::move(t)); + } + + for(auto &thread : tv) { + thread.join(); + } + + return 0; +} + + + + +/* + 多线程顺序打印 +*/ + +#include +#include +#include + + +int k = 0; + +pthread_mutex_t mutex; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +void *fun1(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); //加锁 + + while(k%3 != 0) { + pthread_cond_wait(&cond, &mutex); //条件不满足,则阻塞等待 + } + + printf("A\n"); + k++; + // sleep(1); + + pthread_mutex_unlock(&mutex); // 解锁 + pthread_cond_broadcast(&cond); // 唤醒阻塞在此条件变量上的所有线程 + } + +} + +void *fun2(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k%3 != 1) { + pthread_cond_wait(&cond, &mutex); + } + + printf("B\n"); + k++; + // sleep(1); + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + + +void *fun3(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k%3 != 2) { + pthread_cond_wait(&cond, &mutex); + } + + printf("C\n"); + k++; + // sleep(1); + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + + } + +} + +int main() +{ + pthread_mutex_init(&mutex, NULL); //初始化一个互斥锁(可以直接使用静态初始化) + + pthread_t tid1, tid2, tid3; + + pthread_create(&tid1, NULL, fun1, NULL); + pthread_create(&tid2, NULL, fun2, NULL); + pthread_create(&tid3, NULL, fun3, NULL); + + // 阻塞等待线程回收 + pthread_join(tid1, NULL); + pthread_join(tid2, NULL); + pthread_join(tid3, NULL); + + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); + + return 0; +} + + + +/* + 模拟猴子吃桃问题 + 生产者和消费者问题 +*/ + +// 参看CSDN IPC收藏夹 + +#include +#include +#include + +#define COUNT 7 + +int int_grow_number = 0; +int int_eat_number = 0; + +pthread_mutex_t lock; +pthread_cond_t can_eat = PTHREAD_COND_INITIALIZER; //通知猴子可以吃桃了 +pthread_cond_t can_grow = PTHREAD_COND_INITIALIZER; //通知桃树需要长桃子了 + + +void *eat(void *arg) +{ + while(1) + { + pthread_mutex_lock(&lock); + + //如果吃完了所有的桃子,则阻塞 + if(int_grow_number == int_eat_number) { + pthread_cond_wait(&can_eat, &lock); + } + + if(int_grow_number == -1) { + printf("猴子已经吃饱了\n"); + } + else { + int_eat_number++; + printf("猴子正在吃第 %d 个桃子 \n", int_eat_number); + } + + // std::cout << int_grow_number << std::endl; + // printf("%d\n", int_grow_number); + + sleep(1); + + pthread_cond_signal(&can_grow); //通知桃树长桃子 + pthread_mutex_unlock(&lock); + + if(int_grow_number == -1) break; + } + +} + + +void *grow(void *arg) +{ + while(1) + { + pthread_mutex_lock(&lock); + + //如果生成的桃子猴子还没有吃完,则阻塞等待猴子吃 + if(int_grow_number > int_eat_number) { + pthread_cond_wait(&can_grow, &lock); + } + + if(int_grow_number >= COUNT) { + int_grow_number = -1; + printf("本次喂食结束\n"); + } + else { + int_grow_number++; + printf("桃树正在长第 %d 个桃子\n", int_grow_number); + } + + pthread_cond_signal(&can_eat); //通知猴子吃桃子 + pthread_mutex_unlock(&lock); + + if(int_grow_number == -1) break; + } + +} + +int main() +{ + pthread_t th_peach, th_monkey; + + //初始化互斥锁, 条件变量在定义的时候已经静态初始化了 + pthread_mutex_init(&lock, NULL); // 互斥锁也可以静态初始化 + + pthread_create(&th_peach, NULL, eat, NULL); + pthread_create(&th_monkey, NULL, grow, NULL); + + pthread_join(th_peach, NULL); + pthread_join(th_monkey, NULL); + + pthread_mutex_destroy(&lock); + pthread_cond_destroy(&can_eat); + pthread_cond_destroy(&can_grow); + + return 0; +} \ No newline at end of file diff --git a/Campus_interview/Makefile b/Campus_interview/Makefile new file mode 100644 index 0000000..251940d --- /dev/null +++ b/Campus_interview/Makefile @@ -0,0 +1,5 @@ +demo : demo.cc + g++ demo.cc -o demo -lpthread + +test : test.cc + g++ test.cc -o test \ No newline at end of file diff --git a/Campus_interview/MeiTuan.cc b/Campus_interview/MeiTuan.cc new file mode 100644 index 0000000..5a5e56c --- /dev/null +++ b/Campus_interview/MeiTuan.cc @@ -0,0 +1,342 @@ + +/* + 求二叉树的最小深度和最大深度 +*/ + +//求二叉树的最大深度(Lc第104题) + +int maxDepth(TreeNode *root) +{ + if(root == nullptr) return 0; + + return 1 + std::max(maxDepth(root->left), maxDepth(root->right)); +} + + +//求二叉树的最小深度(错误解法) +// 1 +// 2 +// 3 +//如果是这么一颗二叉树,则用下面的算法返回结果为1,但实际结果应该为3 + +int minDepth(TreeNode *root) +{ + if(root == nullptr) return 0; + + return 1 + std::min(minDepth(root->left), minDepth(root->right)); +} + +//正确解法 + +int minDepth(TreeNode *root) +{ + if(root == nullptr) return 0; + + //左子树为空,返回右子树的深度 + if(root->left == nullptr) { + return 1 + minDepth(root->right); + } + + //右子树为空,返回左子树的深度 + if(root->right == nullptr) { + return 1 + minDepth(root->left); + } + + //左右子树都不为空,返回左右子树深度的最小值 + return std::min(minDepth(root->left), minDepth(root->right)) + 1; +} + + + + +/* + 序列化与反序列化二叉树(Lc第297题) +*/ + +std::string serialize(TreeNode *root) +{ + if(root == nullptr) return "#"; + + return std::to_string(root->val) + "," + serialize(root->left) + "," + serialize(root->right); +} + + +TreeNode* deserialize(std::string data) +{ + std::stringstream in(data); + + return deserializeCore(in); +} + +TreeNode* deserializeCore(std::stringstream &in) +{ + std::string val; + getline(in, val, ','); + + if(val == "#") return nullptr; + + TreeNode *root = new TreeNode(std::stoi(val)); + root->left = deserializeCore(in); + root->right = deserializeCore(in); + + return root; +} + + + +/* + 写一个宏计算两个数之中的较小者,三个数之中的较小者(要求不用if else 语句) +*/ + +//求两个数之间的最小值 +//方法一:这种方法不好 +#define MIN(a, b) ((a) < (b) ? (a) : (b)) //加括号防止预处理展开的错误 + +//方法二:(宏里面如果有多行代码则需要使用 {} ) +#define MIN(a, b) ({ \ + typeof(a) m_x = (a); \ + typeof(b) m_y = (b); \ + (m_x < m_y) ? m_x : m_y; \ +}) + +//1.typeof关键字用来获得变量的数据类型, +//2.宏定义的实现,用{}作为宏整体,里面是一个代码块,语句用";"隔开 +//3.当宏的实现很长的时候,使用换行符 "\" 换到下一行, 注意 "\"的后面不允许有一个空格 +//4.使用输入数据的类型定义局部变量 m_x, m_y 实现对原始数据的保护 +//5.宏实现不能使用 ";" 结尾 + + +//求三个数之间的最小值(宏定义里面没有return语句) +#define MIN(x, y, z) ({\ + typeof(x) m_x = (x);\ + typeof(y) m_y = (y);\ + typeof(z) m_z = (z);\ + m_x < m_y ? (m_x < m_z ? m_x : m_z) : (m_y > m_z ? m_z : m_y);\ +}) + + +//附:写一个函数计算三个数中的较小者(不能使用if else 语句) + +int min(int x, int y, int z) +{ + return x < y ? (x < z ? x : z) : (y > z ? z : y); +} + + +//附:写一个宏交换两个数的值 +#define swap(x, y) ({\ + typeof(x) tmp = x;\ + x = y;\ + y = tmp;\ +}) + +#define swap(x,y) ({\ + x = x^y;\ + y = x^y;\ + x = x^y;\ +}) + +#define swap(x,y) ({\ + x = x + y; \ + y = x - y;\ + x = x - y;\ +}) + + +/* + 链表和数组实现栈和队列 +*/ + +struct stack { + int *data; + int top; //top初始化为-1表示这是一个空栈 + + stack(int n = 0) : data(new int[n]), top(-1) {} + + ~stack() { + delete data; + } + + //判断栈是否满 + bool isFull() + { + if(top == sizeof(data)/sizeof(int) - 1) return true; + else return false; + } + + //判断是否空 + bool isEmpty() + { + if(top == -1) return true; + else return false; + } + + //压入栈 + bool push(int num) + { + if(isFull()) return false; + + data.[++top] = num; + + return true; + } + + //弹出栈 + bool pop() + { + if(isEmpty()) return false; + + --top; + + return true; + } +}; + + +//链表实现栈 + +struct ListNode { + int val; + ListNode *next; + + ListNode(int x) : val(x), next(nullptr) {} +}; + +struct stack { + ListNode *top; + int count; //记录栈的个数,由于是链表存储,则判断栈空或者满时不需要遍历链表 + + stack() : top(nullptr), count(0) {} + + bool push(int num) + { + ListNode *pNode = new(std::nothrow) ListNode(num); + if(pNode == nullptr) return false; + + pNode->next = top; + top = pNode; + count++; + + return true; + } + + bool pop() + { + if(count == 0) return false; + + ListNode *pNode = top(); + top = top->next; + + delete pNode; + return true; + } +}; + + +/* + 1 + -2 3 + 4 -5 6 -7 + 8 9 + + 给出一个二叉树,层序遍历该二叉树,但是规定节点为负数算作虚节点,不能算进层数,遇到虚节点直接打印其子节点(子节点要再是虚节点再打印其非虚子节点) + 如上面节点打印 {1,4,8,9,3,6} +*/ + +//使用双端队列 +//1.如果当前节点的值大于0,则正常加入到队列末端 +//2.如果当前节点的值小于0,则先将右节点加入到队头,再将左节点加入队头 + +void traversal(TreeNode *root) +{ + if(root == nullptr) return; + + std::deque dq; + dq.push_back(root); + + while(!dq.empty()) + { + auto cur = dq.front(); dq.pop_front(); + + if(cur->val > 0) { + printf("%d\n", cur->val); + } + + if(cur->val < 0) { + if(cur->right) dq.push_front(cur->right); + if(cur->left) dq.push_front(cur->left); + } + else { + if(cur->left) dq.push_back(cur->left); + if(cur->right) dq.push_back(cur->right); + } + } + +} + + +/* + 快手二面:给定一组关系(child,parent),返回树的祖先 + + 如:(2,1) (3,1) (5,4), (2,1)子节点为2,父节点为1, (3,1)代表子节点为3,父节点为1 + 这颗树形如 + 1 4 + / \ | + 2 3 5 + + 要求返回节点1,和节点4,注意返回的根节点要求可以通过给定的子节点指针的指向遍历到其所有子节点 +*/ + +struct TreeNode { + int val; + std::vector childNode; + TreeNode(int m_val) : val(m_val), isRoot(0) {} +}; + +std::unordered_set hash; //判断某个节点是否存在 + +std::unordered_map parent; //用来存储节点对应的父亲节点 + +std::vector parse(std::vector> relation) +{ + std::vector res; + + for(int i = 0; i < relation.size(); i++) + { + int childId = relation[i][0], parentId = relation[i][1]; + + if(hash.count(parentId)) + { + TreeNode *pParent = nullptr; + for(auto &node : res) { + if(node->val == parentId) { + pParent = node; + break; + } + } + + TreeNode *pChild = new TreeNode(childId); + + pParent->childNode.push_back(pChild); + parent[pChild] = pParent; + } + else + { + TreeNode *pParent = new TreeNode(parentId); + TreeNode *pchild = new TreeNode(childId); + pParent->childNode.push_back(pChild); + parent[pChild] = pParent; + res.push(pParent); + } + } + + std::vector ans; + for(auto &node : res) + { + if(!parent.count(node)) ans.push_back(node); + } + + return ans; +} + + diff --git a/Campus_interview/NetEase.cc b/Campus_interview/NetEase.cc new file mode 100644 index 0000000..c86f59f --- /dev/null +++ b/Campus_interview/NetEase.cc @@ -0,0 +1,149 @@ + +/* + 设计一个公平的扑克牌洗牌程序 +*/ + +#include +#include + +void shuffle(std::vector &nums); + +int main() { + std::vector nums = {1,2,3,4,5,6,7,8}; + + shuffle(nums); + + return 0; +} + + +void shuffle(std::vector &nums) +{ + srand(time(0)); + + for(int i = nums.size() - 1; i > 0; i--) { + int j = random() % (i+1); // 生成一个下标范围为[0,i]的随机数 + std::swap(nums[i], nums[j]); + } + + for(int &num : nums) { + std::cout << num << " "; + } + + std::cout << std::endl; +} + + +/* + 给定一个等概率生成0-4的随机数生成器,用这个生成器实现等概率生成0-6 +*/ + +int rand4() +{ + return rand()%5; //生成[0,4]之间的随机数 +} + +int rand6() +{ + /* + while(1) + { + int num = 5*rand4() + rand4(); + if(num < 21) { + return num%7; + } + } + */ + //写成上面或者下面这种都可以 + + int num = 5*rand4() + rand4(); + + while(num > 20) + { + num = 5*rand4() + rand4(); + } + + return num%7; +} + + +/* + rand5生成rand7 +*/ + +//生成1~5之间的随机数 +int rand5() +{ + return rand()%5 + 1; +} + +int rand7() +{ + //必须乘以5这样能够保证所有数出现的概率是相同的 + int result = 5*(rand5()-1) + rand5(); //result的范围为[1,25],这里面的数出现的概率都是相同的,去除掉22-25 + + //或者写成这样, int result = INT_MAX; + + while(result > 21) { + result = 5*(rand5()-1) + rand5(); + } + + return result%7 + 1; +} + + +/* + Leetcode第253题:会议室(必须要会) + 参看Leetcode题型总结 +*/ + + + +/* + 连续子数组和为k的最大长度 + 如:{3,4,1,7,8},和为15的最长子数组为{3,4,1,7} + + 附:给定一个字符串,由字符"0"和"1"组成,找到含有相同数量的"0"和"1"的最长子串的长度; + 如:输入"01001001",输出4,满足要求的最长子串为 "1001" + 思路:将字符串的'0'换成-1则等价于求和为0的最长子串 +*/ + +int findMaxLength(std::vector &nums, int target) +{ + std::unordered_map hash; + hash[0] = -1; + + int n = nums.size(); + int res = 0; + int sum = 0; + + for(int i = 0; i < n; i++) { + sum += nums[i]; + if(hash.count(sum-target)) res = std::max(res, i - hash[sum-target]); + hash[sum] = i; + } + + return res == 0 ? -1 : res; +} + + +//附加题 +int findMaxLength(const std::string &str) +{ + std::unordered_map hash; + hash[0] = -1; + + int n = str.size(); + int res = 0; + int sum = 0; + + for(int i = 0; i < str.size(); i++) { + if(str[i] == '0') sum += -1; + else if(str[i] == '1') sum += 1; + + if(hash.count(sum)) res = std::max(res, i - hash[sum]); + else hash[sum] = i; //注意:只有当sum不存在的时候才更新,因为求的是最长的长度 + } + + return res; +} \ No newline at end of file diff --git a/Campus_interview/Search&&Sort.cc b/Campus_interview/Search&&Sort.cc new file mode 100644 index 0000000..19f342e --- /dev/null +++ b/Campus_interview/Search&&Sort.cc @@ -0,0 +1,592 @@ + +/* +* +* 查找和排序 +* +*/ + +/* + 递归实现二分查找 +*/ + +int findNum(std::vector &nums, int left, int right, int target) +{ + if(left > right) return -1; + + int mid = left + ((right-left) >> 1); + if(nums[mid] < target) { + return findNum(nums, mid + 1, right, target); + } + else if(nums[mid] > target) { + return findNum(nums, left, mid - 1, target); + } + + return mid; +} + + + + +//冒泡排序 +//思想:由下往上,两两比较,将最小的数冒泡到最上面(也就是数组的首部) + +//时间复杂度最好为O(n),这时数组是顺序的,只需要做(n-1)比较 +//最差为O(n^2),这时数组恰好为逆序的 +//平均就是O(n^2) + +void bubbleSort(std::vector &nums) +{ + bool flag = true; + + for(int i = 0; i < nums.size() && flag; i++) + { + flag = false; + for(int j = nums.size() - 2; j >= i; j--) + { + if(nums[j] > nums[j+1]) { + std::swap(nums[j], nums[j+1]); + flag = true; + } + } + } + +} + + + +//选择排序 +//思想:每一趟依次找到最小的元素与首部元素进行交换 + +//时间复杂度:最好最差和平均都是O(n^2),因为无论数据是否有序,比较的次数都是一样多 + +void selectSort(std::vector &nums) +{ + for(int i = 0; i < nums.size(); i++) + { + int min = i; + for(int j = i + 1; j < nums.size(); j++) { + if(nums[min] > nums[j]) { + min = j; + } + } + + if(i != min) { + std::swap(nums[i], nums[min]); + } + } + +} + + + +// 插入排序 +// 思想:将一个新的元素插入到已经排好序的序列中 + +// 时间复杂度:最好为O(n),此时数组本身是有序的,只需(n-1)比较 +// 最差情况O(n^2),此时数组恰好是倒序的 +// 平均情况为O(n^2) + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < nums[i-1]) + { + int tmp = nums[i]; + int j = i-1; + for(; nums[j] > tmp && j >= 0; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } + +} + + + +//希尔排序 +//思想:引入了一个增量,将相隔某个"增量"的记录组成一个子序列,实现跳跃式的移动,从而使得排序效率更高 +//注意:增量序列的最后一个增量必须是1才行 + +//时间复杂度:最好为O(n^1.3) +//最差为O(n^2) +//注意:希尔排序的增量的选取对算法时间复杂度很重要 + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + do { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) //注意:这里下标从0开始,所以i=gap,不是书中的gap+1 + { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j = i-gap; + for(; nums[j] > tmp && j >= 0; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + } while(gap > 1); + +} + + +//上面使用了do~while循环,这里直接使用while循环 +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + while(gap >= 1) + { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) + { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j = i - gap; + for(; nums[j] > tmp && j >= 0; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + if(gap == 1) break; //避免死循环,当跨度等于1直接跳出 + } + +} + + + + +//堆排序 +//思想:将所有数据构造成一个大顶堆或者小顶堆 + +//时间复杂度:可以看出堆排序对原始记录的状态并不敏感,所以最好最差和平均复杂度都为O(nlogn) +//新建一个堆是针对非终端节点(非叶子节点)的,对于每个非终端节点来说,最多比较两次,所以时间复杂度为O(n) +//在正式排序时,取堆顶和重建堆的时间复杂度为O(nlogn) +//所以总的时间复杂度为O(n+nlogn) + +void heapSort(std::vector &nums) +{ + int len = nums.size() - 1; + + for(int i = len/2; i >= 1; i--) { //建成大顶堆(前面添加的第0个元素不要管,是设置的为了让其下标构成二叉树所做的) + heapAdjust(nums, i, len); + } + + for(int i = len; i > 1; i--) { + std::swap(nums[1], nums[i]); //将堆顶记录和当前未排序的子序列的最后一个记录交换 + heapAdjust(nums, 1, i-1); //将剩下的元素重新调整成大顶堆 + } + +} + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j *= 2) + { + if(j < end && nums[j] < nums[j+1]) j++; + + if(tmp > nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; +} + + + +//归并排序(二路归并) +//时间复杂度最好最差平均情况均为O(nlogn); +//一趟归并需要把拆分开的子序列都遍历一遍,这需要O(n)时间,由完全二叉树的深度知整个归并排序需要logn次 +//所以总的时间复杂度为O(nlogn) + +//由于归并排序在原始过程中需要与原始序列同样数量的存储空间存放归并好的结果以及递归深度为logn的栈空间 +//因此空间复杂度为O(n+logn) + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right-left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, mid, right); + } + +} + +void merge(std::vector &nums, int left, int mid, int right) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right-left+1]; + int teamIndex = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] < nums[rindex]) { + team[teamIndex++] = nums[lindex++]; + } + else { + team[teamIndex++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + team[teamIndex++] = nums[lindex++]; + } + + while(rindex <= right) { + team[teamIndex++] = nums[rindex++]; + } + + for(int i = 0; i < teamIndex; i++) { + nums[left+i] = team[i]; + } + + delete[] team; +} + + + +//快速排序 +//时间复杂度最好为O(nlogn),最差为O(n^2);空间复杂度为O(n) + +void quickSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = partition(nums, left, right); + quickSort(nums, left, mid - 1); + quickSort(nums, mid + 1, right); + } + +} + +int partition(std::vector &nums, int left, int right) +{ + int pivot = nums[left]; + + while(left < right) + { + while(left < right && nums[right] >= pivot) right--; + std::swap(nums[left], nums[right]); + + while(left < right && nums[left] <= pivot) left++; + std::swap(nums[left], nums[right]); + } + + return left; +} + +//快排优化 + +int partition(std::vector &nums, int left, int right) +{ + int mid = left + ((right - left) >> 1); + + //三数取中 + if(nums[left] > nums[right]) std::swap(nums[left], nums[right]); //保证right最大 + if(nums[mid] > nums[right]) std::swap(nums[mid], nums[right]); + if(nums[left] < nums[mid]) std::swap(nums[left], nums[mid]); //保证mid最小 + + int pivotkey = nums[left]; + + while(left < right) + { + while(left < right && nums[right] >= pivotkey) right--; + nums[left] = nums[right]; //使用替换而不是交换 + + while(left < right && nums[left] <= pivotkey) left++; + nums[right] = nums[left]; + } + + nums[left] = pivotkey; + + return left; +} + + +//桶排序: 将待排序序列划分多个范围相同的区间,每个子区间自排序,最后合并 +//桶排序是计数排序的扩展版本,计数排序可以看成每个桶只存储相同的元素,而桶排序每个桶存储一定范围的元素, +//通过映射函数,将待排序数组中的元素映射到各个对应的桶中,对每个桶中的元素进行排序,最后将非空桶中的元素放入到原序列中 +//桶排序应该尽可能保证元素分散均匀,否则当所有数据集中在一个桶中时,桶排序失效 + +//时间复杂度:对于待排序序列为N,共分为M个桶 +//N次循环,每个元素装入到对应的桶中 +//M次循环,对每个桶中的元素进行排序(每个桶N/M个元素) + +//时间复杂度度: O(N) + O(M*(N/M*log(N/M))) = O(N) + O(Nlog(N/M)) +//当 N = M 时,时间复杂度为 O(N) + +//空间复杂度 O(N + M) M个桶以及N个数据 + +void bucketSort(std::vector &nums) +{ + int maxVal = INT_MIN, minVal = INT_MAX; + + for(const int &n : nums) { + maxVal = std::max(maxVal, n); + minVal = std::min(minVal, n); + } + + //计算桶的数量 + int bucketNum = (maxVal - minVal)/nums.size() + 1; //桶的数量向上取整,每个桶里存放nums.size()个元素 + //第一个桶的元素范围为 [minVal, minVal+n-1]; //n为数组的长度 + + std::vector> buckets(bucketNum, std::vector()); + + //每个元素放入桶 + for(int i = 0; i < nums.size(); i++) { + int num = (nums[i] - minVal)/nums.size(); + buckets[num].push_back(nums[i]); + } + + //对每个桶进行排序 + for(int i = 0; i < bucketNum; i++) { + sort(buckets[i].begin(), buckets[i].end()); + } + + //下面的这部分代码可以直接放在上面的循环,每个桶排好序后就直接插入 + + //将桶中的元素赋值到原序列 + int index = 0; + for(int i = 0; i < bucketNum; i++) { + for(int j = 0; j < buckets[i].size(); j++) { + nums[index++] = buckets[i][j]; + } + } + +} + + +//Leetcode第164题:利用桶排序 + +int maximumGap(std::vector &nums) +{ + if(nums.size() < 2) return 0; + + int minVal = INT_MAX, maxVal = INT_MIN; + for(const int &n : nums) { + minVal = std::min(minVal, n); + maxVal = std::max(maxVal, n); + } + + int n = nums.size(); + int bucketNum = (maxVal - minVal)/n + 1; + + if(maxVal == minVal) return 0; //表明所有元素都相等 + + //记录桶中是否存在元素以及桶中每个元素的最大和最小值 + std::vector hasNum(bucketNum, 0); + std::vector mins(bucketNum), maxs(bucketNum); + + for(int i = 0; i < n; i++) + { + //计算桶编号 + int num = (nums[i] - minVal)/n; + mins[num] = hasNum[num] ? std::min(mins[num], nums[i]) : nums[i]; + maxs[num] = hasNum[num] ? std::max(maxs[num], nums[i]) : nums[i]; + hasNum[num] = 1; + } + + //计算前一个桶的最大值和后一个桶的最小值之差就是最大的diff.不用管桶内数据,因为桶内的数据差肯定要比桶外的数据差小 + int diff = maxs[0] - mins[0]; //防止只有一个桶 + int preMax = maxs[0]; + for(int i = 1; i < bucketNum; i++) { + if(hasNum[i]) { + diff = std::max(diff, mins[i] - preMax); + preMax = maxs[i]; + } + } + + return diff; +} + + + +// 计数排序 : 计数排序是一种非基于比较的排序,它的优势在于对一定范围内的整数排序时,它的时间复杂度为O(n+k)(k是整数的范围),快于任何比较排序算法 +// 其牺牲空间换时间,需要额外的空间存储每个数出现的次数 +// 计数排序是稳定的排序算法 +// <剑指>面试题11 + +void sortAges(std::vector &ages) +{ + int n = ages.size(); + + std::vector timesOfAge(100, 0); + + for(int i = 0; i < n; i++) { + timesOfAge[ages[i]]++; + } + + int index = 0; + for(int i = 0; i < 100; i++) { + for(int j = 0; j < timesOfAge[i]; j++) { + ages[index++] = i; + } + } + +} + + +//计算逆序对(归并排序) <剑指>面试题51 + +int reversePairs(std::vector &nums) +{ + return mergeSort(nums, 0, nums.size() - 1); +} + +int mergeSort(std::vector &nums, int left, int right) +{ + if(left >= right) return 0; + + int mid = left + ((right - left) >> 1); + + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + + std::vector tmp(right - left + 1); + int index = 0; + + int lindex = left, rindex = mid + 1; + + while(lindex <= mid && rindex <= right) //这和剑指上的思路不同,这是从左往右合并判断 + { + if(nums[lindex] <= nums[rindex]) { //注意:这是小于等于 + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + else { + tmp[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + + while(rindex <= right) { + tmp[index++] = nums[rindex++]; + } + + for(int i = 0; i < index; i++) { + nums[left + i] = tmp[i]; + } + + return count; +} + + + +int mergeSort(std::vector &nums, int left, int right) +{ + if(left >= right) return 0; + + int mid = left + ((right - left) >> 1); + + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + + std::vector tmp(right - left + 1); + int index = right - left; + + int lindex = mid, rindex = right; + + while(lindex >= left && rindex >= mid + 1) + { + if(nums[lindex] > nums[rindex]) { //从右往左合并并判断,但这里不能使用'=' + count += rindex - mid; + tmp[index--] = nums[lindex--]; + } + else { + tmp[index--] = nums[rindex--]; + } + } + + while(lindex >= left) { + tmp[index--] = nums[lindex--]; + } + + while(rindex >= mid + 1) { + tmo[index--] = nums[rindex--]; + } + + for(int i = 0; i < tmp.size(); i++) { + nums[left+i] = tmp[i]; + } + + return count; +} + + + +//Leetcode第315题 : 返回逆序个数数组 + +void mergeSort(std::vector> &v, std::vector &count, int left, int right) +{ + if(left >= right) return; + + int mid = left + ((right - left) >> 1); + + mergeSort(v, count, left, mid); + mergeSort(v, count, mid + 1, right); + + int i = left, j = mid + 1; + std::vector> tmp(right - left + 1); + int k = 0; + + while(i <= mid && j <= right) + { + if(v[i].first <= v[j].first) { + count[v[i].second] += j - (mid + 1); + tmp[k++] = v[i++]; + } + else { + tmp[k++] = v[j++]; + } + } + + while(i <= mid) { + count[v[i].second] += j - (mid + 1); + tmp[k++] = v[i++]; + } + + while(j <= right) { + tmp[k++] = v[j++]; + } + + for(int i = 0; i < tmp.size(); i++) { + v[left+i] = tmp[i]; + } + +} + + +std::vector countSmaller(std::vector &nums) +{ + std::vector count(nums.size(), 0); + + std::vector> v; + for(int i = 0; i < nums.size(); i++) { + v.push_back({nums[i], i}); + } + + mergeSort(v, count, 0, nums.size() - 1); + + return count; +} diff --git a/Campus_interview/SenseTime.cc b/Campus_interview/SenseTime.cc new file mode 100644 index 0000000..3acc2c9 --- /dev/null +++ b/Campus_interview/SenseTime.cc @@ -0,0 +1,132 @@ + +/* + C语言实现函数重载(C语言不能函数不能同名,使用函数指针去除掉这个限制) + + 使用函数指针来实现,重载的函数不能使用相同名称,只是类似的实现了函数重载功能 + 重载函数使用可变参数 +*/ + +void func_int(void *a) +{ + printf("%d\n", *(int*)a); +} + +void func_double(void *b) +{ + printf("%f\n", *(double*)b); +} + +typedef void (*ptr)(void *); + +void c_func(ptr p, void *param) +{ + p(param); +} + + +int main() { + int a = 23; + double b = 23.23; + + c_func(func_int, &a); + c_func(func_double, &b); + + return 0; +} + + +/* + C语言实现继承和多态(动态多态) +*/ + + +typedef void(*func)(); //定义一个函数指针来实现对成员函数的继承 + +//父类 +struct A { + func fun; //由于C语言结构体中不能包含函数,故只能用函数指针在类外实现 +}; + +//子类 +struct B { + struct A m_a; //子类中定义一个基类的对象来实现对父类的继承 +}; + +void fA() { //父类的调用函数 + printf("A::\n"); +} + +void fB() { //子类的调用函数 + printf("B::\n"); +} + + +int main() +{ + A a; + B b; + + a.fun = fA; //父类的对象调用父类的函数 + b.m_a.fun = fB; //子类的对象调用子类的函数 + + A* p2 = &a; //定义父类指针指向父类的对象 + p2->fun(); + + p2 = (A*)&b; //让父类指针指向派生类的对象,由于类型不匹配需要强制转换 + p2->fun(); +} + + + +/* + C语言实现封装 + C语言是不存在封装这一特性的,要实现它有两种路径 + 1.利用C语言里面的头文件,在头文件进行声明,在.C文件中进行定义,这样就可以隐藏内部信息,用户只能看到接口和公开的信息,无法知道对象所占的内存 + 2.第二种方法是把私有的信息放在一个不透明的私有变量或者结构体当中,只有类的实现代码才知道私有变量或者结构体的真正含义 +*/ + +// 第1种方法 + +/* + .h文件 +*/ +#ifndef POINT_H +#define POINT_H + +struct Point; + +typedef struct Point point; + +point* new_point(); //创建对象 + +void free_point(point *m_point); //释放空间 + +#endif + + +/* + .C文件 +*/ + +struct Point { + int x; + int y; +}; + +point* new_project() +{ + point *newPoint = (point*)malloc(sizeof(point)); + + return newPoint; +} + +void free_point(point *m_point) +{ + if(m_point != NULL) { + free(m_point); + } +} + + + + diff --git a/Campus_interview/Tencent.cc b/Campus_interview/Tencent.cc new file mode 100644 index 0000000..96c825d --- /dev/null +++ b/Campus_interview/Tencent.cc @@ -0,0 +1,696 @@ +/* + 给一个vector容器只能进行交换,怎么把所有的0都移动到元素末尾 (Leetcode第283题) + 保持其他非0元素的相对位置不变 +*/ + +void moveZeros(std::vector &nums) +{ + if(nums.empty()) return ; + + int cur = 0; + for(int i = 0; i < nums.size(); i++) + { + if(nums[i] != 0) { + std::swap(nums[cur++], nums[i]); + } + } + +} + + +/* + 设定关系(A=1,B=2,...Z=26, AA=27, AB=28,),写一个转换函数,根据规则把一个字符串转换成数字(Leetcode第171题) +*/ + +int titleToNumber(std::string str) +{ + int res = 0; + for(int i = 0; i < str.size(); i++) { + res = res*26 + (str[i]-'A'+1); + } + + return res; +} + + + + +//附:十进制转换成二进制 +std::string transferFrom10To2(int num) +{ + if(num == 0) return "0"; + + std::string res; + while(num) { + int b = num % 2; + res = std::to_string(b) + res; + num = num/2; + } + + return res; +} + +//仿照下面的十进制转16进制的写法,这里转二进制也可以用位运算 +std::string toBin(int num) +{ + if(num == 0) return "0"; + + std::string bin = "01"; + std::string res; + int count = 0; + while(num && count++ < 32) + { + res = bin[num & 1] + res; + num >>= 1; + } + + return res; +} + + +//附:十进制转换成7进制 +//Leetcode第504题 + + +//附:十进制转化成16进制 +//Leetcode第405题 +std::string toHex(int num) +{ + if(num == 0) return "0"; + + std::string hex = "0123456789abcdef"; + std::string res; + int count = 0; + while(num && count++ < 8) + { + res = hex[num & 0xf] + res; + num >>= 4; + } + + return res; +} + + + + +/* + 两数相加 +*/ + +//str1 + str2 (注意:str1和str2均不含负号,是两个正数相加) + +// 直接从尾部相加即可(不需要逆序) + +std::string addTwoNumber(std::string num1, std::string num2) +{ + std::string res; + + int i = 0, j = 0; + int carry = 0; + + while(i >= 0 || j >= 0 || carry) + { + carry += (i >= 0 ? num1[i--]-'0' : 0) + (j >= 0 ? num2[j--]-'0' : 0); + + res = std::to_string(carry%10) + res; + + carry /= 10; + } + + return res; +} + + + + +/* + 两数相减 +*/ + +//我们让 num1 - num2, 且num1的绝对值大于num2,这样方便处理借位 + +//str1 - str2 (注意:str1和str2均不含有负号) + +std::string subTwoNumber(std::string num1, std::string num2) +{ + if(num1 == num2) return "0"; + + //让num1始终比num2大,这样方便处理借位 + bool positive = bigger(num1, num2); + + //num1不大于num2就交换位置 + if(!positive) { + std::swap(num1, num2); + } + + //将num2的长度补齐到和num1一样 + while(num1.size() > num2.size()) { + num2 = "0" + num2; + } + + for(int i = num1.size() -1; i >= 0; i--) + { + //不足就向上一位借位 + if(num1[i] < num2[i] && i > 0) { + num1[i-1]--; + num1[i] += 10; + } + + num1[i] -= (num2[i] - '0'); + } + + std::string res = num1; + + if(res[0] == '0') res = res.substr(1); //去掉开头的0,比如 "100" - "1" = "099" + + //将结果还原 + if(!positive) res = "-" + res; + + return res; +} + +bool bigger(const std::string &num1, const std::string &num2) +{ + if(num1.size() != num2.size()) return num1.size() > num2.size(); + + for(int i = 0; i < num1.size(); i++) { + if(num1[i] != num2[i]) return num1[i] > num2[i]; + } + + //这里返回true或者false都可以,这一句永远不会被执行 + return false; +} + + + +/* + 这种情况能够处理两个数存在负数的情况 + 对上面两个函数的封装 +*/ +std::string AddAndSubTwoNumber(std::string str1, std::string str2) +{ + //两个数均为正数,则直接相加 + if(str1[0] != '-' && str2[0] != '-') return addTwoNumber(str1, str2); + //两个数均为负数 + else if(str1[0] == '-' && str2[0] == '-') { + str1 = str1.substr(1); + str2 = str2.substr(1); + return '-' + addTwoNumber(str1, str2); + } + + //两个数存在一个为负数 + if(str1[0] == '-') { + return subTwoNumber(str2, str1); + } + else { + return subTwoNumber(str1, str2); + } + +} + + +/* + 两数相乘 + Leetcode第43题 +*/ + +std::string multiplyTwoNumber(std::string num1, std::string num2) +{ + int m = num1.size(), n = num2.size(); + std::string res(m + n, '0'); + + for(int i = m-1; i >= 0; i--) { + for(int j = n-1; j >= 0; j--) { + int prod = (num1[i]-'0') * (num2[j]-'0') + (res[i+j+1]-'0'); + res[i+j] += prod/10; + res[i+j+1] = prod%10 + '0'; + } + } + + for(int i = 0; i < res.size(); i++) { + if(res[i] != '0') { + return res.substr(i); + } + } + + return "0"; +} + + + +/* + 判断两个二叉树是否同构 +*/ + +bool Isomorphic(TreeNode *root1, TreeNode *root2) +{ + if(root1 == nullptr || root2 == nullptr) return root1 == root2; + + if(root1->val != root2->val) return false; // 根节点值的不相同,则不同构 + + // 两棵树的左子树均为空或者右子数均为空,则只需比较另外一边子树 + if(root1->left == nullptr && root2->left == nullptr) { + return Isomorphic(root1->right, root2->right); + } + else if(root1->right == nullptr && root2->right == nullptr) { + return Isomorphic(root1->left, root2->left); + } + // 两棵树存在左子树且值相等 + else if(root1->left && root2->left && root1->left->val == root2->left->val) { + return Isomorphic(root1->left, root2->left) && Isomorphic(root1->right, root2->right); + } + else { + return Isomorphic(root1->left, root2->right) && Isomorphic(root1->right, root2->left); + } + +} + + + +/* + 工行有30w个员工,其工卡号码分别为1~30万,抽取十万个员工发放奖品;有一个随机数生成器能生成0~65535的随机数 + 写一个公平的抽奖过程,输出这10万个员工的工卡号码 +*/ + + +//等概率生成一个[1~600]之间的数 +int randNum() +{ + int num; + while(1) + { num = rand()%65536; + if(num > 59999) continue; + else break; + } + + return num%600 + 1; +} + +//等概率生成一个[1~30W]之间的数 +int getNumber() +{ + int num; + while(1) + { + num = 600*(randNum()-1) + randNum(); + if(num > 300000) continue; + else break; + } + + return num; +} + + +/* + 给定一个字符串S和一个字符C,返回一个代表字符串S中每个字符到字符串中的字符C的最短距离的数组 + 如输入S="my_test_str", C='t',输出{3,2,1,0,1,1,0,1,1,0,1} +*/ + +std::vector shortestToChar(std::string s, char c) +{ + //字符串s中不存在字符c则返回为空 + if(s.find(c) == std::string::npos) return {}; + + std::vector index; + for(int i = 0; i < s.size(); i++) { + if(s[i] == c) { + index.push_back(i); + } + } + + std::vector res; + for(int i = 0; i < s.size(); i++) + { + auto it = lower_bound(index.begin(), index.end(), i); + + //1.字符位于第一个c之前 + if(it == index.begin()) { + res.push_back(index.front() - i); + } + //2.字符位于最后一个c之后 + else if(it == index.end()) { + res.push_back(i - index.back()); + } + //3.字符位于多个c之间 + else { + int later = *it; + int prev = *(--it); + int minVal = std::min(later - i, i - prev); + res.push_back(minVal); + } + } + + return res; +} + + + +/* + 给定一个字符串,由字符"0"和"1"组成,找到含有相同数量的"0"和"1"的最长子串的长度;(参见网易校招题) + 如:输入"01001001",输出4,满足要求的最长子串为 "1001" +*/ + +//暴力解法:如果一个长度为n的子串满足条件,则这n个元素加起来的和一定为n/2,且子串长度为偶数 +//时间复杂度O(n^2) + +int findMaxLength(std::string s) +{ + int res = 0; + for(int i = 0; i < s.size(); i++) + { + int sum = 0; + for(int j = i; j < s.size(); j++) + { + int len = j - i + 1; + sum += s[j] - '0'; + + if((len&1) == 0 && sum == (len<<1) && len > res) { + res = len; + } + } + } + + return res; +} + +//解法二: +//思路:定义一个数组dp[i]表示字符串s[0..i]之间的0与1的个数差 +//则问题就转化为在dp中求元素相同但是相距最远的一对数 +//但是如果子串是从开头开始的,则个数差为0,所以需要单独提取出个数差为0的子串比较,个数差为0的子串的长度就是下标+1 + +int findMaxLength(std::string s) +{ + std::vector dp(s.size()); + std::unordered_map> mp; + int res = 0; + + std::vector count(2, 0); + for(int i = 0; i < s.size(); i++) + { + count[s[i]-'0']++; + dp[i] = count[1] - count[0]; //计算1与0的个数差 + if(dp[i] == 0) { + res = i + 1; + } + + mp[dp[i]].push_back(i); + } + + for(auto m : mp) { + res = std::max(res, m.second.back() - m.second.front()); + } + + return res; +} + + + +/* + 给出一个整数N,求小于等于N的所有整数中,哪个数A的每个位上的乘积最大,求出这个数 + (下面这个方法并没有求出这个数) +*/ + +//思路:比它大要么变成9,要么不变 +//变成9就要向上一位借位 + +//找到最大的乘积 +int dfs(int n) +{ + if(n == 0) return 1; + if(n < 10) return n; + + return std::max(dfs(n/10-1)*9, dfs(n/10)*(n%10)); +} + + + +/* + 手动实现vector + //着重注意push_back的书写(未完成) +*/ + + +template +class vector +{ +private: + int num; + T *list; + +public: + vector(int sz = 0); //构造函数 + vector(const vector &a); //复制构造函数 + ~vector(); //析构函数 + + T & operator[] (int i); //对"[]"运算符的重载 + int size() const; //获取元素个数 + void resize(int sz); //更改容易的元素个数 +}; + +template +vector::vector(int sz) { + if(sz >= 0) { + num = sz; + list = new T[sz]; + } + else { + std::cout << "Error!" << std::endl; + exit(1); + } +} + +template +vector::vector(const vector &a) { + num = a.num; + list = new T[num]; + + for(int i = 0; i < num; i++) { + list[i] = a.list[i]; + } +} + +template +vector::~vector() { + delete[] list; +} + +template +T &vector::operator[] (int i) { + if(i >= 0 && i < num) { + return list[i]; + } + else { + std::cout << "Error\n" << std::endl; + exit(1); + } +} + +template +int vector::size() const { + return num; +} + +template +void vector::resize(int sz) { + if(sz < 0) { + std::cout << "Error!\n" << std::endl; + exit(1); + } + + if(sz == num) return; + + T *newList = new T[sz]; + int n = (sz < num) ? sz : num; + + for(int i = 0; i < n; i++) { + newList[i] = list[i]; + } + delete[] list; + list = newList; + num = sz; +} + + +/* + 计算平方根(精确到小数点后四位) +*/ +//参考Leetcode第69题 +//思路:二分 + +double mySqrt(int x) +{ + if(x < 0) return -1; + + double left = 0, right = x; + + while(left <= right) + { + double mid = left + (right-left)/2; + if(fabs(mid*mid - x) < 0.0001) { + return mid; + } + else if(mid*mid < x) { //注意:浮点数二分不需要left=mid+1,因为浮点数的mid一定大于left + left = mid; + } + else if(mid*mid > x) { + right = mid; + } + } + + return -1; +} + + +//开链法实现哈希 + +const int HASHSIZE = 10; //哈希表元素个数 + +struct Node { + char *key; + char *value; + Node *next; + Node() : key(nullptr), value(nullptr), next(nullptr) {} +}; + + +class HashTable +{ +private: + Node *node[HASHSIZE]; + +public: + HashTable() { + memset(node, NULL, sizeof(node)); + } + + + //散列函数,计算key值位于node数组中的位置 + int Hash() {} + + //查找key值 + bool find(const char *key) + { + int index = hash(key); //由散列函数计算出在节点数组node中的下标 + + Node *pNode = node[index]; + while(pNode) + { + //strcmp相同返回0 + if(!strcmp(pNode->key, key)) return true; + + pNode = pNode->next; + } + + return false; //表示未查找到 + } + + //插入键值对 + bool insert(const char *key, char *value) + { + Node *pNode = find(key); + + //key值不存在,则插入 + if(pNode == NULL) + { + int index = hash(key); + pNode = (Node*)malloc(sizeof(Node)); + + if(pNode == NULL) return false; //申请失败则返回false + + pNode->key = key; + pNode->value = value; + node[index] = pNode; + } + + //key值已经存在,则更新value值 + pNode->value = value; + + return true; + } + + //删除某个key + bool deleteKey(const char *key) + { + Node *pNode = find(key); + if(pNode == NULL) return false; //不存在该key值 + + //找到要删除节点的上一个节点prev,将prev指向要删除节点的下一个节点 + int index = hash[key]; + if(node[index] == pNode) { + free(pNode); //不存在哈希冲突,也就是该位置链表只有一个节点 + pNode = NULL; + } + else { //存在哈希冲突 + Node *prev = node[index]; + while(prev->next != pNode) { + prev = prev->next; + } + prev->next = pNode->next; //上面的Node必须提供一个默认的构造函数,否则这里会报错,因为假设 1->2, 我现在删除2,将1指向2的下一个,没有默认构造函数2的next指针未初始化 + free(pNode); //则将其赋值给prev->next就是错误的 + pNode = NULL; + } + + pNode = NULL; + return true; + } +}; + + + +/* + 用数组实现一个循环队列 + //参考Leetcode第622题 +*/ + +int data[10000]; + +int head; + +int tail; + +//初始化当前队列 +void initQueue() +{ + head = 0; + tail = 0; +} + + +int push(int val) +{ + //判断队列是否满 + if((tail + 1)%(10000) == head) return 0; + + data[tail] = val; + + //尾指针向后移动一位 + tail = (tail + 1)%(10000); + + return 1; //返回1表示插入成功 +} + +int pop(int *val) +{ + if(head == tail) return 0; //队列为空则返回0 + + *val = data[head]; + + //头指针往后移动一位 + head = (head + 1)%(10000); + + return 1; //返回1表示弹出成功 +} + +//队列满的判断 +bool isFull() +{ + if((tail + 1)%10000 == head) return true; + + return false; +} + +//队列的长度 +int lenQueue() +{ + return (10000 + tail - head)%(1000); +} diff --git a/Campus_interview/YuanFuDao.cc b/Campus_interview/YuanFuDao.cc new file mode 100644 index 0000000..650d9a6 --- /dev/null +++ b/Campus_interview/YuanFuDao.cc @@ -0,0 +1,118 @@ + +/* + [][][]+[][][]=[][][] + 将1-9的数字填入上式使得等式成立 +*/ + +#include +#include + +void dfs(std::vector &nums, std::vector &count, int step); +int count = 0; + +int main() { + std::vector nums(10); + std::vector visited(10, 0); //这个数组用来记录哪个数被填写过 + + dfs(nums, visited, 1); + + std::cout << count/2 << std::endl; + + return 0; +} + +void dfs(std::vector &nums, std::vector &visited, int step) +{ + if(step > 9) { + if(nums[1]*100 + nums[2]*10 + nums[3] + nums[4]*100 + nums[5]*10 + nums[6] == nums[7]*100 + nums[8]*10 + nums[9]) { + count++; + printf("%d%d%d + %d%d%d = %d%d%d\n", nums[1], nums[2], nums[3], nums[4], nums[5], nums[6], nums[7], nums[8], nums[9]); + } + return ; + } + + for(int i = 1; i <= 9; i++) + { //i没有被填入过 + if(!visited[i]) + { + nums[step] = i; + visited[i] = 1; + + dfs(nums, count, step + 1); + + visited[i] = 0; + } + } + +} + + +/* + 用C语言写一个函数,将字符串里面的空格全部删除掉,返回删除的空格数 +*/ + +int delete_blanks(char *str) +{ + int len = strlen(str); + int cur = 0; + + for(int i = 0; i < len; i++) { + if(str[i] == ' ') continue; + else str[cur++] = str[i]; + } + + //循环出来后cur的值就是删除后的字符串元素个数 + str[cur] = '\0'; + + return len - cur; +} + + +/* + 最大重叠区间数目 (注意:是求最大重叠区间数目,不是所有重叠的区间数目) + + 有一个party,一个记录仪记录下了每个人到达的时间start和离开的时间end, 也就是每个人在party的时间为 (start,end) + 已知 start = {1,2,10,5,5}, end = {4,5,12,9,12}, 代表第一个人在party的时间为(1,4), 第二个人(2,5), 第三个人(9,12) + 求出这个party同一时段内最多接纳了多少人 + + 思路:按照时间对start和end进行排序,之后合并 + 时刻 类型 人数 + 1 S 1 + 2 S 2 + 4 E 1 + 5 S 2 + 5 S 3 人数最多为3人 + 5 E 2 + 9 E 1 + 10 S 2 + 12 E 1 + 12 E 1 +*/ + +int findMaxGuests(std::vector &start, std::vector &end) +{ + int n = start.size(); + + sort(start.begin(), start.end()); + sort(end.begin(), end.end()); + + int i = 0, j = 0; + int count = 0, res = 0; + + while(i < n && j < n) + { + if(start[i] <= end[j]) { + count++; + res = std::max(res, count); + i++; + } + else { + count--; + j++; + } + } + + return res; +} + + diff --git a/Campus_interview/demo b/Campus_interview/demo new file mode 100755 index 0000000..9073d1b Binary files /dev/null and b/Campus_interview/demo differ diff --git a/Campus_interview/demo.cc b/Campus_interview/demo.cc new file mode 100644 index 0000000..c60ae92 --- /dev/null +++ b/Campus_interview/demo.cc @@ -0,0 +1,652 @@ + +/* + 多线程顺序打印 +*/ +/* +#include +#include +#include + +pthread_mutex_t mutex; + +int k = 0; + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +void *fun1(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); //加锁 + + while(k%3 != 0) { + pthread_cond_wait(&cond, &mutex); + } + + printf("A\n"); + k++; + + pthread_mutex_unlock(&mutex); // 解锁 + pthread_cond_broadcast(&cond); // 唤醒阻塞在此条件变量上的所有线程 + + // sleep(1); + } + +} + +void *fun2(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k%3 != 1) { + pthread_cond_wait(&cond, &mutex); + } + + printf("B\n"); + k++; + + pthread_mutex_unlock(&mutex); //解锁 + pthread_cond_broadcast(&cond); //解除阻塞的条件变量 + + // sleep(1); + } + +} + + +void *fun3(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); //加锁 + + while(k%3 != 2) { + pthread_cond_wait(&cond, &mutex); + } + + printf("C\n"); + k++; + + pthread_mutex_unlock(&mutex); //解锁 + pthread_cond_broadcast(&cond); //解除阻塞的条件变量 + + // sleep(1); + } + +} + +int main() +{ + pthread_mutex_init(&mutex, NULL); //初始化一个互斥锁 + + pthread_t tid1, tid2, tid3; + + pthread_create(&tid1, NULL, fun1, NULL); + pthread_create(&tid2, NULL, fun2, NULL); + pthread_create(&tid3, NULL, fun3, NULL); + + // 阻塞等待线程回收 + pthread_join(tid1, NULL); + pthread_join(tid2, NULL); + pthread_join(tid3, NULL); + + pthread_mutex_destroy(&mutex); + + return 0; +} + + +/* + 模拟猴子吃桃问题 + 生产者和消费者问题 +*/ +/* + +// 参看CSDN IPC收藏夹 + +#include +#include +#include + +#define COUNT 7 + +int int_grow_number = 0; +int int_eat_number = 0; + +pthread_mutex_t lock; +pthread_cond_t can_eat = PTHREAD_COND_INITIALIZER; //通知猴子可以吃桃了 +pthread_cond_t can_grow = PTHREAD_COND_INITIALIZER; //通知桃树需要长桃子了 + + +void *eat(void *arg) +{ + while(1) + { + pthread_mutex_lock(&lock); + + //如果吃完了所有的桃子,则阻塞 + if(int_grow_number == int_eat_number) { + pthread_cond_wait(&can_eat, &lock); + } + + if(int_grow_number == -1) { + printf("猴子已经吃饱了\n"); + } + else { + int_eat_number++; + printf("猴子正在吃第 %d 个桃子 \n", int_eat_number); + } + + // std::cout << int_grow_number << std::endl; + // printf("%d\n", int_grow_number); + + sleep(1); + + pthread_cond_signal(&can_grow); //通知桃树长桃子 + pthread_mutex_unlock(&lock); + + if(int_grow_number == -1) break; + } + +} + + +void *grow(void *arg) +{ + while(1) + { + pthread_mutex_lock(&lock); + + //如果生成的桃子猴子还没有吃完,则阻塞等待猴子吃 + if(int_grow_number > int_eat_number) { + pthread_cond_wait(&can_grow, &lock); + } + + if(int_grow_number >= COUNT) { + int_grow_number = -1; + printf("本次喂食结束\n"); + } + else { + int_grow_number++; + printf("桃树正在长第 %d 个桃子\n", int_grow_number); + } + + pthread_cond_signal(&can_eat); //通知猴子吃桃子 + pthread_mutex_unlock(&lock); + + if(int_grow_number == -1) break; + } + +} + +int main() +{ + pthread_t th_peach, th_monkey; + + //初始化互斥锁, 条件变量在定义的时候已经静态初始化了 + pthread_mutex_init(&lock, NULL); + + pthread_create(&th_peach, NULL, eat, NULL); + pthread_create(&th_monkey, NULL, grow, NULL); + + pthread_join(th_peach, NULL); + pthread_join(th_monkey, NULL); + + return 0; +} + +#include + + +// pthread_cond_t thread1 = PTHREAD_COND_INITIALIZER; +// pthread_cond_t thread2 = PTHREAD_COND_INITIALIZER; +// pthread_cond_t thread3 = PTHREAD_COND_INITIALIZER; + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +int k = 0; + +void *fun1(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&lock); + + while(k%3 != 0) { + pthread_cond_wait(&cond, &lock); + } + + printf("A\n"); + k++; + + pthread_mutex_unlock(&lock); + pthread_cond_broadcast(&cond); + + } + +} + + +void *fun2(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&lock); + + while(k%3 != 1) { + pthread_cond_wait(&cond, &lock); + } + + printf("B\n"); + k++; + + pthread_mutex_unlock(&lock); + pthread_cond_broadcast(&cond); + + } + +} + +void *fun3(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&lock); + + while(k%3 != 2) { + pthread_cond_wait(&cond, &lock); + } + + printf("C\n"); + k++; + + pthread_mutex_unlock(&lock); + pthread_cond_broadcast(&cond); + + } + +} + + +int main() { + pthread_t tid1, tid2, tid3; + + pthread_create(&tid1, NULL, fun1, NULL); + pthread_create(&tid2, NULL, fun2, NULL); + pthread_create(&tid3, NULL, fun3, NULL); + + pthread_join(tid1, NULL); + pthread_join(tid2, NULL); + pthread_join(tid3, NULL); + + pthread_mutex_destroy(&lock); + + return 0; +} + + + +#include +#include +#include + +int delete_blanks(char *str) +{ + int len = strlen(str); + int cur = 0; + + for(int i = 0; i < len; i++) { + if(str[i] == ' ') continue; + else str[cur++] = str[i]; + } + + str[cur] = '\0'; + + return len - cur; +} + + +int delete_blanks(char *str); + +int main() { + + // int a = (int)(((int*)0) + 4); + + // printf("%d\n", a); + + // char *src = "hello"; + + // char *dest = NULL; + + // int len = strlen(src); + + // dest = (char*)malloc(len + 1); + // char *d = dest; + // char *s = src + len - 1; + + // while(len-- != 0) { + // *(d++) = *(s--); + // } + // *d = '\0'; + + // printf("%s\n", dest); + + // free(dest); + + // char str[20] = "h e l lo"; + + // printf("%d\n", delete_blanks(str)); + + // printf("%s\n", str); + + char buf[4] = {0x12, 0x34, 0x56, 0x78}; + + printf("%x\n", *(short*)&buf[3]); + + return 0; +} + + +int k = 0; + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +void *func1(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k%3 != 0) { + pthread_cond_wait(&cond, &mutex); + } + + printf("A\n"); + k++; + // sleep(1); + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + + +void *func2(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k%3 != 1) { + pthread_cond_wait(&cond, &mutex); + } + + printf("B\n"); + k++; + // sleep(1); + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + +void *func3(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k%3 != 2) { + pthread_cond_wait(&cond, &mutex); + } + + printf("C\n"); + k++; + // sleep(1); + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + +int main() +{ + pthread_t tid1, tid2, tid3; + + pthread_create(&tid1, NULL, func1, NULL); + pthread_create(&tid2, NULL, func2, NULL); + pthread_create(&tid3, NULL, func3, NULL); + + pthread_join(tid1, NULL); + pthread_join(tid2, NULL); + pthread_join(tid3, NULL); + + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); + + return 0; +} + +*/ + +/* + +#include +#include +#include + + +/* + C语言实现函数重载(C语言不能函数不能同名,使用函数指针去除掉这个限制) + + 使用函数指针来实现,重载的函数不能使用相同名称,只是类似的实现了函数重载功能 + 重载函数使用可变参数 +*/ +/* +void func_int(void *a) +{ + printf("%d\n", *(int*)a); +} + +void func_double(void *b) +{ + printf("%f\n", *(double*)b); +} + +typedef void (*ptr)(void *); + +void c_func(ptr p, void *param) +{ + p(param); +} + + +void printStirng2() +{ + std::unique_lock lock(mut); + + while(1) + { + // std::cout << "hello" << std::endl; + while(k != 2) cv.wait(lock); + + for(int i = 0; i < s2.size(); i++) { + std::cout << s2[i] ; + } + + // std::cout << "B" << std::endl; + sleep(1); + + k = 1; + cv.notify_all(); + } + +} + +/* +void printStirng3() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 3) cv.wait(lock); + + std::cout << "C" << std::endl; + sleep(1); + + k = 1; + cv.notify_all(); + } + +}*/ +/* +int main() { + int a = 23; + double b = 23.23; + + c_func(func_int, &a); + c_func(func_double, &b); + + return 0; +} + + +std::mutex mut; +std::condition_variable cv; + +int k = 1; + +std::string s1 = "abcd"; +std::string s2 = "1234"; + +// void printStirng1() +// { +// std::unique_lock lock(mut); + +// while(1) +// { +// std::cout << "Hi" << std::endl; +// while(k != 1) cv.wait(lock); + +// for(int i = 0; i < s1.size(); i++) { +// std::cout << s1[i]; +// } +// // std::cout << "A" << std::endl; +// sleep(1); + +// k = 2; +// cv.notify_all(); +// } + +// } + +void printString1() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s1.size(); i++) + { + while(k != 1) cv.wait(lock); + std::cout << s1[i] << std::endl; + sleep(1); + + k = 2; + + cv.notify_all(); + } + } + +} + + +void printString2() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s2.size(); i++) + { + while(k != 2) cv.wait(lock); + std::cout << s2[i] << std::endl; + + sleep(1); + + k = 1; + + cv.notify_all(); + } + } + +} + + + +int main() { + // std::thread t1(printString1); + // std::thread t2(printString2); + // // std::thread t3(printStirng3); + + // t1.join(); + // t2.join(); + // t3.join(); + + // int i = 0, j = 1, k = 2; + // int num = ++i||--j&&++k; + + // std::cout << num << std::endl; + + int i = 217; + int arr[i] = {0}; + + return 0; +}*/ + + + +#include +#include +#include +#include +#include + +template +void g(Args ... args) { + std::cout << sizeof...(Args) << std::endl; + std::cout << sizeof...(args) << std::endl; +} + +template +auto fcn(It beg, It end) -> decltype(*beg) { + return *beg; +} + + + + + +std::vector intersect(std::vector &nums1, std::vector &nums2) +{ + std::unordered_map mp; + for(const int &n : nums1) mp[n]++; + + std::vector res; + + for(const int &n : nums2) { + if(mp.count(n) && mp[n]-- > 0) res.push_back(n); + } + + return res; +} + diff --git a/Campus_interview/test b/Campus_interview/test new file mode 100755 index 0000000..2778caf Binary files /dev/null and b/Campus_interview/test differ diff --git a/Campus_interview/test.cc b/Campus_interview/test.cc new file mode 100644 index 0000000..734560c --- /dev/null +++ b/Campus_interview/test.cc @@ -0,0 +1,11429 @@ + + +/* + +利用快慢指针原理:设置两个指针*search,*mid都指向单链表的头结点;(重点在于区分头结点和头指针) +其中*search的移动速度是*mid的两倍; +则当*search指向末尾节点的时候,则mid就正好在中间了 + +*/ + +//对链表个数为奇数,恰好能找到中间节点; +//对链表个数为偶数,如链表个数为4,则找到的是第2号节点 +// int GetMidNode(LinkList L, Elemtype *e) +// { +// LinkList search, mid; +// mid = search = L; //使mid和search指向链表头结点 + +// while(search->next != NULL) +// { +// if(search->next->next != NULL){ +// search = search->next->next; +// mid = mid->next; +// }else{ +// search = search->next; +// } + +// } + +// *e = mid->data; //*e表示链表中间节点的数据 + +// return 1; + +// } + + +// bool fun(int number) +// { +// if(number < 0) return false; +// int s = number; +// int y = 0; +// do{ +// y = y*10 + s%10; +// s = s/10; + +// }while(s != 0); + +// if(y == number){ +// return true; +// }else{ +// return false; +// } + +// } + +// #include + +// int main(){ +// int n = 1201; + +// if(fun(n)){ +// std::cout << "Success" << std::endl; +// }else{ +// std::cout << "Failure" << std::endl; +// } + +// return 0; + +// } + +/* +#include + +void print(); + +int main(){ + print(); + + printf("\n"); + + return 0; +} + + + +void print(){ + char a; + scanf("%c", &a); + if(a != '#') print(); //以#作为结束标记 + if(a != '#') printf("%c", a); + +} +*/ + +/* +#include + +int main(){ + int a[5] = {2}; + std::cout << a[4] << std::endl; + + return 0; +} + +*/ + +/* +#include + +//声明两个全局变量 +int findValue[2000] = {2}; //题目说了有足够的内存,可以这样使用数组 +static int find = 1; //find为findVlaue数组中元素的个数;即素数的个数 + +bool adjust(int value); + +int main(){ + for(int i = 2; i <= 25; i++) adjust(i); + + for(int i = 0; i < find; i++){ + std::cout << findValue[i] << " "; + } + std::cout << std::endl; + + return 0; +} + +bool adjust(int value) +{ + if(value == 2){ + return true; + }else{ + for(int i = 0; i < find; i++){ + if(value % findValue[i] == 0) return false; //判断当前数是否能被已查找出的素数整除 + } //能被已经查找出的素数整除的数当然就不是素数 + findValue[find++] = value; //此等同于find[find] = value; find++; + } //不能写成findValue[++find] = value;否则会报错 + +} +*/ + + +/* +struct ListNode{ + int val; + ListNode *next; + ListNode() : val(0), next(nullptr) {} + ListNode(int x) : val(x), next(nullptr) {} + ListNode(int x, ListNode *next) : val(x), next(next) {} +}; + + + + +ListNode* getMidNode(ListNode *head) +{ + ListNode *fast = head; + ListNode *slow = head; + + while(fast->next != nullptr){ + if(fast->next->next != nullptr){ + fast = fast->next->next; + slow = slow->next; + }else{ + slow = slow->next; + } + } + + return slow; + +} +*/ + + + + + +/* +//这是小甲鱼的版本 +typedef int Elemtype; + +void GetMidNode(LinkList L, Elemtype *e) +{ + LinkList search, mid; //search代表快指针,mid代表慢指针 + mid = search = L; //使mid和search指向链表第一个结点 + + while(search->next != NULL) + { + if(search->next->next != NULL){ + search = search->next->next; + mid = mid->next; + }else{ + search = search->next; + } + + } + + *e = mid->data; //*e表示链表中间节点的数据 + +} +*/ + +// #include + +// void swap1(int &x, int &y); +// void swap2(int &x, int &y); + +// int main(){ +// int num_1 = 5, num_2 = 10; +// swap2(num_1, num_2); +// std::cout << "num_1 = " << num_1 << std::endl; +// std::cout << "num_2 = " << num_2 << std::endl; + +// return 0; +// } + +// //解法一:基于加减法 +// void swap1(int &x, int &y) +// { +// x = x-y; +// y = y+x; +// x = y-x; +// } + + +// //解法二:基于位运算 +// void swap2(int &x, int &y) +// { +// x = x^y; +// y = x^y; +// x = x^y; + +// } + +/* + +#include + +void fun(int n, int m) ; + +int main(){ + fun(4, 6); + std::cout << std::endl; + + return 0; +} + + + +void fun(int n, int m) //n是总人数,m是序数 +{ + bool a[n+1] = {0}; //用1表示被杀,0表示未被杀掉;刚开始所有人都是0(未被杀) + int f = 0, t = 0, s = 0; + + do{ + ++t; + if(t > n) t = 1; + if(!a[t]) s++; + if(s == m){ + s = 0; + std::cout << t << " "; + a[t] = 1; //该人被杀,标记为1 + f++; + } + + }while(f != n); + +} + + +// void fun(int n, int m) //n是总人数,m是序数 +// { +// bool a[n+1] = {0}; //a是标记数组 +// int f = 0, t = 0, s = 0; + +// do{ +// t++; +// if(t > n) t = 1; +// if(!a[t]) s++; +// if(s == m){ +// s = 0; +// std::cout << t << " "; +// a[t] = 1; //标记位为1表示该人被杀 +// f++ +// } +// }while(f != n) + +// } + +*/ + + +/* +#include +#include +#include + + +std::string transfer(int num); +std::string transferFrom10To2(int num); + +int main() { + int num = 100; + // std::cout << transfer(num) << std::endl; + + // std::string transferFrom10To2(int num); + std::cout << transferFrom10To2(num) << std::endl; + + // shuffle(nums); + // std::string str = "I love you"; + // std::cout << reverseWords(str) << std::endl; + + // srand(time(0)); + // std::cout << rand()%4 << std::endl; + + + return 0; +} + + +std::string transferFrom10To2(int num) +{ + // std::string res; + // while(num) { + // int b = num % 2; + // res = std::to_string(b) + res; + // num = num/2; + // } + if(num == 0) return "0"; + + std::string bin = "01"; + std::string res; + int count = 0; + while(num && count++ < 32) + { + res = bin[num & 1] + res; + num >>= 1; + } + + return res; +} +/* + +void OddInOddEvenInEven(std::vector &nums) +{ + if(nums.size() <= 1) return; + + int i = 0, j = 1; + while(i < nums.size() && j < nums.size()) + { + //判断nums[i]是否为偶数,如果为偶数则向前进两位到达下一个偶数位 + while(i < nums.size() && (nums[i]%2 == 0)) { + i += 2; + } + + while(j < nums.size() && (nums[j]%2 == 1)) { + j += 2; + } + + if(i < nums.size() && j < nums.size()) { + std::swap(nums[i], nums[j]); + } + } + +} + + +void shuffle(std::vector &nums) +{ + srand(time(0)); + + for(int i = nums.size() - 1; i > 0; i--) { + int j = random() % (i+1); + std::swap(nums[i], nums[j]); + } + + for(int &num : nums) { + std::cout << num << " "; + } + + std::cout << std::endl; +} + +std::string reverseStr(std::string &str) +{ + if(str.empty()) return str; + + int left = 0, right = 0; + while(right <= str.size()) + { + if(str[right] == ' ' || right == str.size()) { + reverse(str.begin() + left, str.begin() + right); + left = right + 1; + } + + right++; + } + + + reverse(str.begin(), str.end()); + + return str; +} + +void moveZeros(std::vector &nums) +{ + if(nums.empty()) return ; + + int cur = 0; + for(int i = 0; i < nums.size(); i++) + { + if(nums[i] != 0) { + std::swap(nums[cur++], nums[i]); + } + } + +} + +int firstMissingPositive(std::vector &nums) +{ + int j = 1; + std::vector tmp(nums.size(), 0); + for(int i = 0; i < tmp.size(); i++) { + tmp[i] = j++; + } + + for(int i = 0; i < nums.size(); i++) { + if(find(tmp[i], nums)) continue; + else return tmp[i]; + } + + return nums.size() + 1; +} + +bool find(int target, std::vector &nums) +{ + for(int i = 0; i < nums.size(); i++) { + if(nums[i] == target) return true; + } + + return false; +} + + +int firstMissingPositive(std::vector &nums) +{ + int n = nums.size(); + for(int i = 0; i < n; i++) + { + while(nums[i] > 0 && nums[i] <= n && nums[nums[i]-1] != nums[i]) { + std::swap(nums[i], nums[nums[i]-1]); + } + } + + for(int i = 0; i < n; i++) { + if(nums[i] != i+1) { + return i + 1; + } + } + + return n + 1; //如果数据是完整的,比如nums={1,2,3},则应该返回(数组长度+1) +} + +*/ +/* +#include +#include + +void* myMemcpy(void *dest, void *src, unsigned int size); + +int main() { + // int a[10] = {0,1,2,3,4,5,6,7,8,9}; + // unsigned int n = 3; + // void *p = memcpy(a + 3, a, n); + + // char *target = (char*)malloc(sizeof(char)*10); + char target[] = "0123456789"; + char target1[] = "0123456789"; + memcpy(target + 3*sizeof(char), target, 5*sizeof(char)); + myMemcpy(target1 + 3*sizeof(char), target1, 5*sizeof(char)); + + puts(target); + puts(target1); + + return 0; +} + +void* myMemcpy(void *dest, void *src, unsigned int size) +{ + char *pdest = NULL, *psrc = NULL; + + //判断是否存在内存重叠 + if((src < dest) && (char*)src + size > (char*) dest) + { + //从后往前复制 + psrc = (char*)src + size - 1; + pdest = (char*)dest + size - 1; + + while(size--) { + *pdest-- = *psrc--; + } + } + else + { + //不存在内存重叠则从前往后复制 + psrc = (char*)src; + pdest = (char*)dest; + + while(size--) { + *pdest++ = *psrc++; + } + } + + return (void*)dest; +} + +*/ + +/* +#include +#include + +int main() { + std::vector nums = {4,4,4,1}; + int n = nums.size(); + for(int i = 0; i < n; i++) { + nums[(nums[i]-1)%n] += n; //注意:这里要取余,因为前面的数会改变掉后面的数的值 + } + + for(int i = 0; i < n; i++) { + nums[i] = (nums[i]-1)/n; + } + + for(int num:nums) { + std::cout << num << " "; + } + std::cout << std::endl; + + return 0; +} +*/ + +/* +#include +#include + +void bubbleSort(std::vector &nums); +void selectSort(std::vector &nums); +void insertSort(std::vector &nums); +void shellSort(std::vector &nums); +void heapAdjust(std::vector &nums, int start, int end); +void heapSort(std::vector &nums, int len); +void mergeSort(std::vector &nums, int left, int right); +void merge(std::vector &nums, int left, int mid, int right); +void quickSort(std::vector &nums, int left, int right); +int partition(std::vector &nums, int left, int right); + + +int main() { + std::vector nums = {3,0,2,1,5,6}; + + // bubbleSort(nums); + // selectSort(nums); + // insertSort(nums); + // shellSort(nums); + // heapSort(nums, nums.size()-1); + quickSort(nums, 0, nums.size() - 1); + + for(int num : nums) { + std::cout << num << " "; + } + std::cout << std::endl; + + return 0; +} + + +//冒泡排序 +//思想:由下往上,两两比较,将最小的数冒泡到最上面(也就是数组的首部) + +//时间复杂度最好为O(n),这时数组是顺序的,只需要做(n-1)比较 +//最差为O(n^2),这时数组恰好为逆序的 +//平均就是O(n^2) + +void bubbleSort(std::vector &nums) +{ + bool flag = true; + + for(int i = 0; i < nums.size() && flag; i++) + { + flag = false; + for(int j = nums.size() - 2; j >= i; j--) + { + if(nums[j] > nums[j+1]) { + std::swap(nums[j], nums[j+1]); + flag = true; + } + } + } + +} + + +//选择排序 +//思想:每一趟依次找到最小的元素与首部元素进行交换 + +//时间复杂度:最好最差和平均都是O(n^2),因为无论数据是否有序,比较的次数都是一样多 + +void selectSort(std::vector &nums) +{ + for(int i = 0; i < nums.size(); i++) + { + int min = i; + for(int j = i + 1; j < nums.size(); j++) { + if(nums[min] > nums[j]) { + min = j; + } + } + + if(i != min) { + std::swap(nums[i], nums[min]); + } + } + +} + + +//插入排序 +//思想:将一个新的元素插入到已经排好序的序列中 + +//时间复杂度:最好为O(n),此时数组本身是有序的,只需(n-1)比较 +//最差情况O(n^2),此时数组恰好是倒序的 +//平均情况为O(n^2) + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < nums[i-1]) + { + int tmp = nums[i]; + int j; + for(j = i-1; nums[j] > tmp && j >= 0; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } + +} + + +//希尔排序 +//思想:引入了一个增量,将相隔某个"增量"的记录组成一个子序列,实现跳跃式的移动,从而使得排序效率更高 +//注意:增量序列的最后一个增量必须是1才行 + +//时间复杂度:最好为O(n^1.3) +//最差为O(n^2) +//注意:希尔排序的增量的选取对算法时间复杂度很重要 + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + do { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) //注意:这里下标从0开始,所以i=gap,不是书中的gap+1 + { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j; + for(j = i-gap; nums[j] > tmp && j >= 0; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + } while(gap > 1); + +} + + +//堆排序 +//思想:将所有数据构造成一个大顶堆或者小顶堆 + +//时间复杂度:可以看出堆排序对原始记录的状态并不敏感,所以最好最差和平均复杂度都为O(nlogn) +//新建一个堆是针对非终端节点的,对于每个非终端节点来说,最多比较两次,所以时间复杂度为O(n) +//在正式排序时,取堆顶和重建堆的时间复杂度为O(nlogn) +//所以总的时间复杂度为O(n+nlogn) + +void heapSort(std::vector &nums, int len) +{ + for(int i = len/2; i > 0; i--) { //建成大顶堆(前面添加的第0个元素不要管,是设置的为了让其下标构成二叉树所做的) + heapAdjust(nums, i, len); + } + + for(int i = len; i > 1; i--) { + std::swap(nums[1], nums[i]); //将堆顶记录和当前未排序的子序列的最后一个记录交换 + heapAdjust(nums, 1, i-1); //将剩下的元素重新调整成大顶堆 + } + +} + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j*=2) + { + if(j < end && nums[j] < nums[j+1]) j++; + + if(tmp > nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; +} + + + +//归并排序(二路归并) + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right-left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, mid, right); + } + +} + +void merge(std::vector &nums, int left, int mid, int right) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right-left+1]; + int teamIndex = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] < nums[rindex]) { + team[teamIndex++] = nums[lindex++]; + } + else { + team[teamIndex++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + team[teamIndex++] = nums[lindex++]; + } + + while(rindex <= right) { + team[teamIndex++] = nums[rindex++]; + } + + for(int i = 0; i < teamIndex; i++) { + nums[left+i] = team[i]; + } + + delete[] team; +} + + +//快速排序 + +void quickSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int pivot = partition(nums, left, right); + quickSort(nums, left, pivot - 1); + quickSort(nums, pivot + 1, right); + } + +} + +int partition(std::vector &nums, int left, int right) +{ + int pivot = nums[left]; + + while(left < right) + { + while(left < right && nums[right] >= pivot) right--; + std::swap(nums[left], nums[right]); + + while(left < right && nums[left] <= pivot) left++; + std::swap(nums[left], nums[right]); + } + + return left; +} +*/ + +/* +#include +#include +#include + +// template +// struct greater : public binary_function { +// bool operator()(const T &x, const T &y) const { +// return x > y; +// } +// }; + +// template +// struct less : public binary_function { +// bool operator()(const T &x, const T &t) const { +// return x < y; +// } +// }; + +bool myfunction(int i, int j) { + return i < j; +} + +void shellSort(std::vector &nums); +void insertSort(std::vector &nums); +void heapAdjust(std::vector &nums, int start, int end); +void heapSort(std::vector &nums, int len); + +union Test +{ + int num; + char c; +}; + +// void GetIntA(int &p) { +// p = (int*)malloc(sizeof(int)); +// return; +// } + + +class A +{ +public: + void print(int n) { + std::cout << n << std::endl; + } + +}; + + +int main() { + // union Test test; + // test.num = 1; + + // std::cout << (int)test.c << std::endl; + // // int a = 0x00001234; + + // // char *p = (char*)(&a); + + // // printf("0x%x\n", (int)*p); + // // printf("0x%x\n", (int)*(p+1)); + // // printf("0x%x\n", (int)*(p+2)); + + // // std::cout << a << std::endl; + + // int a = (int)(((int*)0) + 4); + // int *p = 0; + // p = p + 4; + + // // int a = (int)p; + // int a = static_cast(p); + + // std::cout << a << std::endl; + + // std::string str = "123"; + + // std::cout << sizeof(str) << std::endl; + + // ((A*)0)->print(4); + + // char buf[4] = {0x12, 0x34, 0x56, 0x78}; + + // std::cout << *(short*)(&buf[3]) << std::endl; + + int b = 129; + char c = b; + printf("%d\n", c); + + return 0; +} + +bool isPalindrome(ListNode *head) +{ + if(head->next == nullptr) return true; + + ListNode *slow = head, *fast = head; + + while(fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + } + + slow = reverList(slow); + + while(head && slow) { + if(head->val != slow->val) return false; + head = head->next; + slow = slow->next; + } + + return true; +} + +ListNode* reverList(ListNode *head) +{ + ListNode *prev = nullptr; + + while(head) + { + ListNode *pNext = head->next; + head->next = prev; + prev = head; + head = pNext; + } + + return prev; +} + + + + +void insertSort(std::vector &nums) +{ + for(int j = 1; j < nums.size(); j++) + { + if(nums[j-1] > nums[j]) { + int tmp = nums[j]; + int i = j-1; + for(; i >= 0 && nums[i] > tmp; i--) { + nums[i+1] = nums[i]; + } + nums[i+1] = tmp; + } + } + +} + + +// void shellSort(std::vector &nums) +// { +// int gap = nums.size(); + +// do { +// gap = gap/3 + 1; + +// for(int i = gap; i < nums.size(); i++) +// { +// if(nums[i] < nums[i-gap]) { +// int tmp = nums[i]; +// int j = i - gap; +// for(; j >= 0 && nums[j] > tmp; j -= gap) { +// nums[j+gap] = nums[j]; +// } +// nums[j+gap] = tmp; +// } +// } + + +// }while(gap > 1); + +// } + + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + do { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) + { + if(nums[i-gap] > nums[i]) { + int tmp = nums[i]; + int j = i - gap; + for(; j >= 0 && nums[j] > tmp; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + }while(gap > 1); + +} + +void heapSort(std::vector &nums, int len) +{ + for(int i = len/2; i > 0; i--) { + heapAdjust(nums, i, len); + } + + for(int i = len; i > 1; i--) { + std::swap(nums[1], nums[i]); + heapAdjust(nums, 1, i - 1); + } + +} + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j *= 2) + { + if(j < end && nums[j] < nums[j+1]) j++; + + if(tmp > nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; + +} +*/ +/* +#include +#include + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + +public: + static Singleton& getInstance() + { + static Singleton instance; + return instance; + } + + void print() { + std::cout << "do something..." << std::endl; + } + +}; + +int main() { + // Singleton &demo = Singleton::getInstance(); + // demo.print(); + + return 0; +} +*/ +/* +#include + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton&); + +public: + static Singleton& getInstance() { + static Singleton instance; + return instance; + } + + void print() { + std::cout << "do something..." << std::endl; + } + +}; + +int main() { + // Singleton::getInstance().print(); + Singleton demo; + + return 0; +} + + +//1.实现赋值运算符函数 + +class CMyString +{ +public: + CMyString(char *pData = nullptr); + CMyString(const CMyString &str); + ~CMyString(); + +private: + char *m_pData; + +}; + +//第一种解法 +CMyString& CMyString::operator=(const CMyString &str) +{ + if(this != &str) + { + delete[] m_pData; + m_pData = nullptr; + + m_pData = new char[strlen(str) + 1]; //存在一个隐患,如果分配内存失败,则是会抛出异常的 + strcpy(m_pData, str.m_pData); //则m_pData是一个空指针,这样非常容易导致程序崩溃 + } //也即CMyString的实例也不存在了,在申请内存之前释放掉了 + + return *this; +} + +//第二种写法:考虑线程安全 +CMyString& CMyString::operator=(const CMyString &str) +{ + if(this != &str) + { + CMyString strTmp(str); //先申请一个临时对象申请够足够的内存,如果程序崩溃了原对象还存在 + + char *pTmp = strTmp.m_pData; + strTmp.m_pData = m_pData; //strTmp的m_pData指向的是实例之前的内存,所以相当于自动调用析构函数释放内存 + m_pData = pTmp; + } + + return *this; +} +*/ +/* +#include +#include +#include +#include +/* +class string +{ +private: + char* pStr; + unsigned int size; + +public: + string(const char *str = nullptr) + { + if(str == nullptr) { + pStr = new char[1]; + *pStr = '\0'; + size = 0; + } + else { + int len = strlen(str); + pStr = new char[len + 1]; + strcpy(pStr, str); + size = len; + } + } + + string(const string &str) : pStr(new char[str.size + 1]) + { + std::cout << "拷贝构造函数"<< std::endl; + strcpy(pStr, str.pStr); + size = str.size; + } + + string operator=(const string &str) + { + if(this != &str) + { + // string strTmp(str); + + // char *pSTrTmp = strTmp.pStr; + // strTmp.pStr = pStr; + // pStr = pSTrTmp; + + char *pStr = new char[str.size + 1]; + strcpy(pStr, str.pStr); + size = str.size; + } + + return *this; + } + + ~string() + { + // std::cout << "析构" << std::endl; + delete[] pStr; + } +}; + +*/ +/* +bool judgePoint(std::vector &nums); +bool isValid(std::vector nums, int tmp); + + +int main() { + std::vector nums = {9,2,1,1}; + + std::cout << judgePoint(nums) << std::endl; + + return 0; +} + + +//加减乘除计算24点(不包含括号运算) +//典型的DFS + +//思路:四个数字轮流拿出来充当第一个数,并将拿出来的数从数组中删除 +//之后递归,判断这个拿出来的数与下一个数的和,差,商,积,计算完后将下一个数踢出数组 +//以此递归知道数组中已经没有元素,判断此时和是否为24点 + +bool judgePoint(std::vector &nums) +{ + std::vector tmpNum = nums; + + for(int i = 0; i < tmpNum.size(); i++) + { + int tmp = tmpNum[i]; + tmpNum.erase(tmpNum.begin() + i); + if(isValid(tmpNum, tmp)) return true; + tmpNum = nums; + } + + return false; +} + +bool isValid(std::vector nums, int tmp) +{ + if(!nums.empty()) + { + for(int i = 0; i < nums.size(); i++) + { + int n = nums[i]; + nums.erase(nums.begin() + i);; + if(isValid(nums, tmp*n) || isValid(nums, tmp+n) || isValid(nums, tmp-n) || (n && isValid(nums,tmp/n))) { + return true; + } + } + } + + if(tmp == 24) return true; + + return false; +} + + +ListNode* mergeKLists(std::vector &lists) +{ + if(lists.empty()) return nullptr; + + int len = lists.size(); + while(len > 1) + { + for(int i = 0; i < len/2; i++) { + lists[i] = mergeTwoList(lists[i], lists[len-1-i]); + } + + len = (len+1) >> 1; + } + + return lists[0]; +} + + +ListNode* mergeTwoList(ListNode*l1, ListNode *l2) +{ + if(l1 == nullptr) return l2; + else if(l2 == nullptr) return l1; + + if(l1->val < l2->val) { + l1->next = mergeTwoList(l1->next, l2); + return l1; + } + else { + l2->next = mergeTwoList(l1, l2->next); + return l2; + } + +} + +ListNode* mergeTwoList(ListNode *l1, ListNode *l2) +{ + ListNode *base = new ListNode(-1); + ListNode *head = base; + + while(l1 && l2) + { + if(l1->val < l2->val) { + base->next = l1; + l1 = l1->next; + } + else { + base->next = l2; + l2 = l2->next; + } + + base = base->next; + } + + base->next = l1 ? l1 : l2; + + return head->next; +} +*/ + +/* +#include +#include +#include + +std::string subTwoNumber(std::string str1, std::string str2); +bool bigger(std::string str1, std::string str2); + +// long long findMaxButtons(std::vector &buttons); + +// int findMaxLength(std::string s); +// void dfs(std::vector &nums, std::vector &count, int pos); + +int main() { + + std::string str1 = "90", str2 = "90"; + + std::cout << subTwoNumber(str1, str2) << std::endl; + + + return 0; +} + +/* +void dfs(std::vector &nums, std::vector &count, int pos) +{ + if(pos > 9) { + if(nums[0]*100 + nums[1]*10 + nums[2] + nums[3]*100 + nums[4]*10 + nums[5] == nums[6]*100 + nums[7]*10 + nums[8]) { + printf("%d%d%d + %d%d%d = %d%d%d\n", nums[0], nums[1], nums[2], nums[3], nums[4], nums[5], nums[6], nums[7], nums[8]); + } + return ; + } + + for(int i = 0; i <= 9; i++) + { + if(count[i] == 1) continue; + nums[pos] = i; //将该位置赋值 + count[i] = 1; //标记已经用过的数 + dfs(nums, count, pos + 1); + count[i] = 0; //回溯 + } + +} + +int findMaxLength(std::string s) +{ + std::vector count(2), dp(s.size()); + + int res = 0; + + for(int i = 0; i < s.size(); i++) + { + count[s[i]-'0']++; + dp[i] = count[1] - count[0]; + if(dp[i] == 0) { + res = i + 1; + } + } + + std::unordered_map> mp; + for(int i = 0; i < dp.size(); i++) { + mp[dp[i]].push_back(i); + } + + for(auto m : mp) { + res = std::max(res, m.second.back() - m.second.front()); + } + + return res; +} + + +long long findMaxButtons(std::vector &buttons) +{ + long long res = 0; + for(int i = 0; i < buttons.size(); i++) { + res += buttons[i] + (buttons[i]-1)*i; + } + + return res; +} +*/ + +/* +std::string subTwoNumber(std::string str1, std::string str2) +{ + std::string res; + if(str1 == str2) { + return "0"; + } + + bool positive = bigger(str1, str2); + + if(!positive) { + std::swap(str1, str2); + } + + while(str2.size() < str1.size()) { + str2 = "0" + str2; + } + + for(int i = str1.size() - 1; i >= 0; i--) + { + if(str1[i] < str2[i] && i > 0) { + str1[i-1]--; + str1[i] += 10; + } + + str1[i] -= (str2[i]-'0'); //注意:这里容易出错 + } + + res = str1; + + if(!positive) { + res = '-' + res; + } + + return res; +} + +bool bigger(std::string str1, std::string str2) +{ + if(str1.size() != str2.size()) return str1.size() > str2.size(); + + for(int i = 0; i < str1.size(); i++) { + if(str1[i] != str2[i]) { + return str1[i] > str2[i]; + } + } + +} + + + +std::string multiplyTwoNumber(std::string num1, std::string num2) +{ + int m = num1.size(), n = num2.size(); + std::string res(m + n, '0'); + + for(int i = m-1; i >= 0; i--) { + for(int j = n-1; j >= 0; j--) { + int prod = (num1[i]-'0')*(num2[j]-'0') + res[i+j+1]; + res[i+j+1] = prod%10; + res[i+j] += prod/10; + } + } + + for(int i = 0; i < res.size(); i++) { + if(res[i] != '0') { + return res.substr(i); + } + } + + return "0"; +} +*/ + + +/* +#include +#include +#include + +void* memcpy(void *dest, void *src, size_t size); + +class Singleton +{ +private: + Singleton(){}; + Singleton(const Singleton&); + Singleton& operator+(const Singleton&); + +public: + static Singleton& getInstance() { + static Singleton demo; + return demo; + } + + void print() { + std::cout << "hello" << std::endl; + } + +}; + + +void* memcpy(void *dest, void *src, size_t size) +{ + if(dest == NULL || src == NULL) return NULL; + + char *psrc = NULL, *pdest = NULL; + + if(src < dest && (char*)src + size > (char*)dest) + { + psrc = (char*)src + size - 1; + pdest = (char*)dest + size - 1; + + while(size--) { + *pdest-- = *psrc--; + } + } + else + { + psrc = (char*)src, pdest = (char*)dest; + while(size--) { + *pdest++ = *psrc++; + } + } + + return (void*)dest; +} + + +class String +{ +private: + char *pStr; + unsigned int size; + +public: + String(const char *str = NULL) + { + if(str == NULL) { + pStr = new char[1]; + *pStr = '\0'; + size = 0; + } + else + { + int len = strlen(str); + pStr = new char[len+1]; + strcpy(pStr, str); + size = len; + } + + } + + String(const String &str) + { + int len = str.size; + pStr = new char[len+1]; + + strcpy(pStr, str.pStr); + size = len; + } + + String& operator=(const String &str) + { + if(this != &str) + { + delete [] pStr; + int len = str.size; + pStr = new char[len+1]; + strcpy(pStr, str.pStr); + size = len; + } + + return *this; + } + + ~String() + { + delete [] pStr; + printf("析构\n"); + } + + void print() { + printf("%s\n", pStr); + } +}; + + + + + +template +class shared_ptr +{ +private: + T *ptr; //实际地址 + int *count; //存放引用计数的地址(这里必须要用地址,因为可能存在多个变量对其更改,使用地址可以多个变量都可以访问) + +public: + shared_ptr(T *pointer = nullptr) + { + ptr = pointer; + + if(ptr == nullptr) { + count = new int(0); + } + else { + count = new int(1); + } + } + + shared_ptr(const shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + count = smartPtr.count; + + (*count)++; + } + + shared_ptr& operator=(const shared_ptr &smartPtr) + { + if(ptr != smartPtr.ptr) + { + //需要先减去原来的指针的引用计数,如果引用计数为0,则需要释放原来的内存再进行赋值 + //但是如果指针原来指向为空,则引用奇数为0,不能再减了 + if(ptr != nullptr) + { + (*count)--; + if((*count) == 0) { + delete ptr; + delete count; + } + } + + ptr = smartPtr.ptr; + count = smartPtr.count; + (*count)++; + } + + } + + //取指针指向的值(返回的是引用) + T& operator*() + { + if(ptr != nullptr) { + return *ptr; + } + } + + //注意:->操作符返回的是地址; p->fun(); 等价于 (*p).fun(); + //使用指针直接->指向函数地址,p需要是一个指针 + T& operator->() { + if(ptr != nullptr) { + return ptr; + } + } + + //只能指针只有当引用计数等于0时才释放指向的内存 + ~shared_ptr() + { + //为空则说明该只能指针没有直接向任何对象,只释放count的内存 + if(ptr == nullptr) { + std::cout << "释放空指针" << std::endl; + delete count; + } + else if(--(*count) == 0) { + delete ptr; + delete count; + } + + } + + //返回引用计数 + int use_count() { + return *count; + } + +}; + + + +int main() { + shared_ptr sm(new int(10)); + + shared_ptr sm2(sm); + + std::cout << sm.use_count() << std::endl; + + shared_ptr sm3; + sm3 = sm; + std::cout << sm.use_count() << std::endl; + + std::cout << *sm3 << std::endl; + + return 0; +} + +int res = INT_MIN; + +int maxPathSum(TreeNode *root) +{ + maxPathSumCore(root); + + return res; +} + +int maxPathSumCore(TreeNode *root) +{ + if(root == nullptr) return 0; + + int leftMax = std::max(0, maxPathSumCore(root->left)); //左子树的最大值(因为路径和的左子树路径也可以是空的) + int rightMax = std::max(0, maxPathSumCore(root->right)); + + res = std::max(res, root->val + leftMax + rightMax); + + return std::max(root->val, root->val + leftMax + rightMax); +} +*/ + + + + + + +/* +int rand4() +{ + return rand()%5; //生成[0,4]之间的随机数 +} + +int rand6() +{ + /* + while(1) + { + int num = 5*rand4() + rand4(); + if(num < 21) { + return num%7; + } + } + */ + /* + //写成上面或者下面这种都可以 + + int num = 5*rand4() + rand4(); + + while(num > 21) + { + num = 5*rand4() + rand4(); + } + + return num%7; +} + +void bucketSort(std::vector &nums) +{ + int maxVal = INT_MIN, minVal = INT_MAX; + + for(const int &n : nums) { + maxVal = std::max(maxVal, n); + minVal = std::min(minVal, n); + } + + //计算桶的数量 + int bucketNum = (maxVal - minVal)/nums.size() + 1; //向上取整 + + std::vector> buckets(bucketNum, std::vector()); + + //每个元素放入桶 + for(int i = 0; i < nums.size(); i++) { + int num = (nums[i]-minVal)/nums.size(); + buckets[num].push_back(nums[i]); + } + + //对每个桶进行排序 + for(int i = 0; i < bucketNum; i++) { + sort(buckets[i].begin(), buckets[i].end()); + } + + //将桶中的元素赋值到原序列 + int index = 0; + for(int i = 0; i < bucketNum; i++) { + for(int j = 0; j < buckets[i].size(); j++) { + nums[index++] = buckets[i][j]; + } + } + +} +*/ +/* +#include +#include +#include +#include + +void bubbleSort(std::vector &nums); +void selectSort(std::vector &nums); +void insertSort(std::vector &nums); +void shellSort(std::vector &nums); +void heapAdjust(std::vector &nums, int start, int end); +void heapSort(std::vector &nums); +void mergeSort(std::vector &nums, int left, int right); +void merge(std::vector &nums, int left, int mid, int right); +void quickSort(std::vector &nums, int left, int right); +int partition(std::vector &nums, int left, int right); +void bucketSort(std::vector &nums); + +int main() { + std::vector nums = {18, 11, 28, 45, 23, 50}; + // std::vector nums = {18, 11, 23}; + + // bucketSort(nums, 0, nums.size() - 1); + bucketSort(nums); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + + +void bubbleSort(std::vector &nums) +{ + bool flag = true; + + for(int i = 0; i < nums.size() && flag; i++) + { + flag = false; + for(int j = nums.size()-2; j >= i; j--) + { + if(nums[j] > nums[j+1]) { + std::swap(nums[j], nums[j+1]); + flag = true; + } + } + } + +} + +void selectSort(std::vector &nums) +{ + for(int i = 0; i < nums.size(); i++) + { + int min = i; + for(int j = i+1; j < nums.size(); j++) + { + if(nums[min] > nums[j]) { + min = j; + } + } + + if(i != min) { + std::swap(nums[min], nums[i]); + } + } + +} + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < nums[i-1]) + { + int tmp = nums[i]; + int j = i-1; + for(; nums[j] > tmp && j >= 0; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } + +} + + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + while(gap >= 1) + { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) + { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j = i - gap; + for(; nums[j] > tmp && j >= 0; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + if(gap == 1) break; + } + +} + + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j *= 2) + { + if(j < end && nums[j] < nums[j+1]) { + j++; + } + + if(tmp >= nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; +} + +void heapSort(std::vector &nums) +{ + int len = nums.size() - 1; + + for(int i = len/2; i > 0; i--) { + heapAdjust(nums, i, len); + } + + for(int i = len; i > 0; i--) { + std::swap(nums[1], nums[i]); + heapAdjust(nums, 1, i-1); + } + +} + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right-left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, mid, right); + } + +} + +void merge(std::vector &nums, int left, int mid, int right) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right - left + 1]; + int teamIndex = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] <= nums[rindex]) { + team[teamIndex++] = nums[lindex++]; + } + else { + team[teamIndex++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + team[teamIndex++] = nums[lindex++]; + } + + while(rindex <= right) { + team[teamIndex++] = nums[rindex++]; + } + + for(int i = 0; i < right-left+1; i++) { + nums[left + i] = team[i]; + } + + delete[] team; +} + + +void quickSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int pivot = partition(nums, left, right); + quickSort(nums, left, pivot - 1); + quickSort(nums, pivot + 1, right); + } + +} + +int partition(std::vector &nums, int left, int right) +{ + int mid = left + ((right - left) >> 1); + + // if(nums[left] > nums[mid]) std::swap(nums[left], nums[mid]); + // if(nums[mid] > nums[right]) std::swap(nums[mid], nums[right]); + // if(nums[mid] < nums[left]) std::swap(nums[left], nums[mid]); + + // if(nums[left] > nums[right]) std::swap(nums[left], nums[right]); + // if(nums[mid] > nums[right]) std::swap(nums[mid], nums[right]); + // if(nums[mid] < nums[left]) std::swap(nums[left], nums[mid]); + + //三数取中 + if(nums[left] > nums[right]) std::swap(nums[left], nums[right]); //保证right最大 + if(nums[mid] > nums[right]) std::swap(nums[mid], nums[right]); + if(nums[left] < nums[mid]) std::swap(nums[left], nums[mid]); //保证mid最小 + + int pivotkey = nums[left]; + + while(left < right) + { + while(left < right && nums[right] >= pivotkey) right--; + // std::swap(nums[left], nums[right]); + nums[left] = nums[right]; + + while(left < right && nums[left] <= pivotkey) left++; + // std::swap(nums[left], nums[right]); + nums[right] = nums[left]; + } + + nums[left] = pivotkey; + + // for(int i = left; i <= right; i++) { + // std::cout << nums[i] << " "; + // } + // std::cout << std::endl; + + return left; +} + + +void bucketSort(std::vector &nums) +{ + int maxVal = INT_MIN, minVal = INT_MAX; + + for(const int &n : nums) { + maxVal = std::max(maxVal, n); + minVal = std::min(minVal, n); + } + + int bucketNum = (maxVal - minVal)/nums.size() + 1; + + std::vector> buckets(bucketNum); + + //每个元素放入桶 + for(const int &n : nums) { + int num = (n - minVal)/nums.size(); + buckets[num].push_back(n); + } + + for(int i = 0; i < buckets.size(); i++) { + sort(buckets[i].begin(), buckets[i].end()); + } + + int index = 0; + for(int i = 0; i < buckets.size(); i++) { + for(int j = 0; j < buckets[i].size(); j++) { + nums[index++] = buckets[i][j]; + } + } + +} +*/ + +/* +#include +#include +#include + +std::string addTwoNumber(std::string num1, std::string num2); +bool bigger(std::string num1, std::string num2); +std::string subTwoNumber(std::string num1, std::string num2); +int findMaxForm(std::vector &strs, int m, int n); + +int main() { + std::vector strs = {"10", "0001", "111001", "1", "0"}; + int m = 5, n = 3; + + findMaxForm(strs, m, n); + + return 0; +} + +std::string addTwoNumber(std::string num1, std::string num2) +{ + reverse(num1.begin(), num1.end()); + reverse(num2.begin(), num2.end()); + + int carry = 0; + int i = 0, j = 0; + std::string res; + + while(i != num1.size() || j != num2.size() || carry) + { + int val1 = (i != num1.size()) ? (num1[i++]-'0') : 0; + int val2 = (j != num2.size()) ? (num2[j++]-'0') : 0; + int sum = val1 + val2 + carry; + carry = sum/10; + res += std::to_string(sum%10); + } + + reverse(res.begin(), res.end()); + + return res; +} + +//我们让 num1 - num2, 且num1的绝对值大于num2,这样方便处理借位 +std::string subTwoNumber(std::string num1, std::string num2) +{ + if(num1 == num2) return "0"; + + bool positive = bigger(num1, num2); + + if(!positive) { + std::string tmp = num1; + num1 = num2; + num2 = tmp; + } + + while(num1.size() > num2.size()) { + num2 = '0' + num2; + } + + for(int i = num1.size() - 1; i >= 0; i--) + { + if(num1[i] < num2[i] && i > 0) { + num1[i-1]--; + num1[i] += 10; + } + + num1[i] -= (num2[i]-'0'); + } + + std::string res = num1; + if(!positive) { + res = "-" + res; + } + + return res; +} + +bool bigger(std::string num1, std::string num2) +{ + if(num1.size() != num2.size()) return num1.size() > num2.size(); + + for(int i = 0; i < num1.size(); i++) { + if(num1[i] > num2[i]) return true; + } + + return false; +} + +// std::string multiplyTwoNumber(std::string num1, std::string num2) +// { +// int m = num1.size(), n = num2.size(); +// std::string res(m + n, '0'); + +// for(int i = m-1; i >= 0; i--) { +// for(int j = n-1; j >= 0; j--) { +// int prod = (num1[i]-'0') * (num2[j]-'0') + (res[i+j+1]-'0'); +// res[i+j] += prod/10; +// res[i+j+1] = std::to_string(prod%10); +// } +// } + +// for(int i = 0; i < res.size(); i++) { +// if(res[i] != '0') { +// return res.substr(i); +// } +// } + +// return "0"; +// } + + +int findMaxForm(std::vector &strs, int m, int n) +{ + std::vector> dp(m + 1, std::vector(n + 1, 0)); + + for(const auto &str : strs) + { + int count0 = count(str.begin(), str.end(), '0'); + int count1 = str.size() - count0; + + for(int i = m; i >= count0; i--) { + for(int j = n; j >= count1; j--) { + dp[i][j] = std::max(dp[i][j], 1 + dp[i-count0][j-count1]); + } + } + + for(int i = 0; i < dp.size(); i++) { + for(int j = 0; j < dp[i].size(); j++) { + std::cout << dp[i][j] << " "; + } + std::cout << std::endl; + } + std::cout << std::endl; + } + + return dp[m][n]; +} + + +bool isMatch(std::string s, std::string p) +{ + int m = s.size(), n = p.size(); + std::vector> dp(m + 1, std::vector(n + 1, 0)); + + dp[0][0] = 1; + for(int j = 1; j <= n; j++) { + if(p[j-1] == '*') { + dp[0][j] = dp[0][j-1]; + } + } + + for(int i = 1; i <= m; i++) { + for(int j = 1; j <= n; j++) { + if(s[i-1] == p[j-1] || p[j-1] == '?') { + dp[i][j] = dp[i-1][j-1]; + } + else if(p[j-1] == '*') { + dp[i][j] = dp[i-1][j-1] || dp[i-1][j] || dp[i][j-1]; + } + } + } + + return dp[m][n]; +}*/ +/* + +#include +#include +#include +#include +#include + +int rand7(); +int rand5(); +double mySqrt(int x); + + +int main() { + std::unordered_multimap hash; + hash.insert({1,4}); + hash.insert({1,3}); + hash.insert({1,2}); + + for(auto item : hash) { + std::cout << item.first << " " << item.second << std::endl; + } + + return 0; +} + +//生成1~5之间的随机数 +int rand5() +{ + return rand()%5 + 1; +} + +int rand7() +{ + //为什么乘以5,这样可以找到离7的倍数最近的21,如果乘以4范围为[1,20],这样得去除掉15-20 + int result = 5*(rand5()-1) + rand5(); //result的范围为[1,25],这里面的数出现的概率都是相同的,去除掉22-25 + while(result > 21) { + result = 5*(rand5()-1) + rand5(); + } + + return result%7 + 1; +} + + +double mySqrt(int x) +{ + if(x < 0) return -1; + + double left = 0, right = x; + + while(left <= right) + { + double mid = left + (right-left)/2; + if(fabs(mid*mid - x) < 0.0001) { + return mid; + } + else if(mid*mid < x) { + left = mid; + } + else if(mid*mid > x) { + right = mid; + } + } + + return -1; +} + +/* +int maxScore(std::vector &nums, int k) +{ + int sum = accumulate(nums.begin(), nums.end(), 0); + + int n = nums.size(); + int minSum = accumulate(nums.begin(), nums.begin() + n-k, 0); + + int resMinSum = minSum; + for(int i = n-k; i < n; i++) { + minSum += nums[i] - nums[i-(n-k)] + if(resMinSum > minSum) { + resMinSum = minSum; + } + } + + return sum - resMinSum; +} + +std::vector preorderTraversal(TreeNode *root) +{ + std::vector res; + if(root == nullptr) return res; + + std::stack sta; + sta.push(root); + + while(!sta.empty()) + { + TreeNode *pNode = sta.top(); sta.pop(); + res.push_back(pNode->val); + + if(pNode->right) { + sta.push(pNode->right); + } + + if(pNode->left) { + sta.push(pNode->left); + } + } + + return res; +} + +std::vector inorderTraversal(TreeNode *root) +{ + std::vector res; + if(root == nullptr) return res; + + std::stack sta; + TreeNode *pNode = root; + + while(pNode || !sta.empty()) + { + while(pNodet) { + sta.push(pNode); + pNode = pNode->left; + } + + pNode = sta.top(); sta.pop(); + res.push(pNode->val); + + pNode = pNode->right; + } + + return res; +} + +std::vector postorderTraversal(TreeNode *root) +{ + std::vector res; + if(root == nullptr) return res; + + std::stack sta; + sta.push(root); + + while(!sta.empty()) + { + TreeNode *pNode = sta.top(); sta.pop(); + res.push_back(pNode->val); + + if(pNode->left) { + sta.push(pNode->left); + } + if(pNode->right) { + sta.push(pNode->right); + } + } + + reverse(res.begin(), res.end()); + + return res; +} +*/ + +/* +int maxArea(std::vector &nums) +{ + int left = 0, right = nums.size() - 1; + int maxArea = 0; + + while(left < right) + { + int wide = right - left; + int hei = nums[left] < nums[right] : nums[left++] ? nums[right--]; + maxArea = std::max(maxArea, hei*wide); + } + + return maxArea; +} + +int trap(std::vector &height) +{ + std::stack sta; + int res = 0; + + for(int i = 0; i < height.size(); i++) + { + while(!sta.empty() && height[i] > height[sta.top()]) { + int midIndex = sta.top(); sta.pop(); + if(!sta.empty()) { + int wide = i - sat.top() - 1; + int hei = std::min(height[i], height[sta.top()]) - height[midIndex]; + res += wide*hei; + } + } + + sta.push(i); + } + + return res; +} + + +int calculateMinimumHP(std::vector> &dungeon) +{ + int m = dungeon.size(), n = dungeon[0].size(); + + std::vector> dp(m + 1, std::vector>(n + 1, INT_MAX)); + dp[m-1][n] = 1; + dp[m][n-1] = 1; + + for(int i = m-1; i >= 0; i--) { + for(int j = n-1; j >= n; j--) { + dp[i][j] = std::min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j]; + } + } + + return dp[0][0]; +} +*/ +/* +#include +#include +#include +#include +#include +#include +#include +#include + +struct Node +{ + int data; + // std::shared_ptr next; + std::weak_ptr next; + + Node(int n) : data(n) {} + + ~Node() { + std::cout << "~Destructor!" << std::endl; + } + +}; + +bool isNumber(std::string s); +bool scanInteger(std::string s, int &i); +bool scanUnsignedInteger(std::string s, int &i); + +int main() { + // std::set mySet; + // std::cout << mySet.capacity() << std::endl; + // std::cout << mySet.size() << std::endl; + // std::shared_ptr p1 = std::make_shared(1); + // std::shared_ptr p2 = std::make_shared(2); + + // p1->next = p2; + // p2->next = p1; + + // std::map hash; + // hash.insert({1,1}); + // hash.insert({2,2}); + // hash.insert({3,3}); + // hash.insert({4,4}); + // hash.insert({5,5}); + + // // for(auto it = hash.begin(); it != hash.end();) + // // { + // // if((it->second&1)) { + // // hash.erase(it++); + // // } + // // else { + // // it++; + // // } + // // } + + // for(std::map::iterator it = hash.begin(); it != hash.end();) + // { + // if(it->second&1) { + // it = hash.erase(it); + // } + // else it++; + // } + + + // for(auto item : hash) { + // std::cout << item.first << " " << item.second << std::endl; + // } + + // std::vector nums; + // nums.push_back(1); + // nums.push_back(2); + // nums.push_back(3); + // nums.push_back(4); + // nums.push_back(4); + + // std::cout << nums.capacity() << std::endl; + + std::cout << isNumber(".") << std::endl; + + return 0; +} + +//匹配模式为 A[.[B]][e|EC] +//由于小数点前可能为空,如果为空,则小数点后一定要有数子 .B[e|Ec] +//[]代表可选项,可以没有,其中A和C都代表可能以'+'或者'-'开头的数字,而B不可能以符号开头 + +bool isNumber(std::string s) +{ + if(s.empty()) return false; + + int i = 0; + bool numeric = scanInteger(s, i); //扫描A部分 + + //扫描B部分 + if(s[i] == '.') { + i++; + numeric = scanUnsignedInteger(s, i) || numeric; //注意这里是或,小数点前面或者后面可能没有数字 + } + + //扫描C部分 + if(s[i] == 'E' || s[i] == 'e') { + i++; + numeric = numeric && scanInteger(s, i); //注意:这里是用与,因为e前面必须要求有数字 + } + + return numeric && (i == s.size()); //判断是否到达了字符串末尾 +} + +bool scanInteger(std::string s, int &i) +{ + if(i >= s.size()) return false; + + if(s[i] == '+' || s[i] == '-') i++; + + return scanUnsignedInteger(s, i); +} + +bool scanUnsignedInteger(std::string s, int &i) +{ + if(i >= s.size()) return false; + + int before = i; + + while(i < s.size()) + { + if(s[i] >= '0' && s[i] <= '9') i++; + else break; + } + + //s中存在无符号数时才返回 + return i > before; +} +*/ + +/* +#include +#include +#include +#include + +std::vector shortestToChar(std::string s, char c); +int findMaxLength(std::string s); +void getMaxNum(int N, int &A); +int dfs(int N, int &A); +int solve(int n); + +int main() { + // std::string s = "my_test_str"; + // char c = 't'; + + // std::vector res = shortestToChar(s, c); + + // for(const int &n : res) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + // std::string s = "01001001"; + + // std::cout << findMaxLength(s) << std::endl; + + // int A = 0, N = 200; + + // getMaxNum(N, A); + + // std::cout << A << std::endl; + + // std::cout << solve(200) << std::endl; + + // int num = solve(200); + int mul = 81; + int num = 200; + + while(num) + { + + } + + + return 0; +} + +std::vector shortestToChar(std::string s, char c) +{ + if(s.find(c) == std::string::npos) return {}; + + std::vector index; + for(int i = 0; i < s.size(); i++) { + if(s[i] == c) { + index.push_back(i); + } + } + + std::vector res; + + for(int i = 0; i < s.size(); i++) + { + auto it = lower_bound(index.begin(), index.end(), i); + + if(it == index.begin()) { + res.push_back(*it - i); + } + else if(it == index.end()) { + res.push_back(i - *(--it)); + } + else { + int later = *it; + int prev = *(--it); + res.push_back(std::min(later - i, i - prev)); + } + } + + return res; +} + +int findMaxLength(std::string s) +{ + std::vector dp(s.size(), 0); + std::unordered_map> hash; + + int res = 0; + + std::vector count(2, 0); + for(int i = 0; i < s.size(); i++) { + count[s[i]-'0']++; + dp[i] = count[1] - count[0]; + if(dp[i] == 0) res = i + 1; + hash[dp[i]].push_back(i); + } + + for(auto it : hash) { + res = std::max(res, it.second.back() - it.second.front()); + } + + return res; +} + +/* +void getMaxNum(int N, int &A) +{ + dfs(N, A); +} + +int dfs(int N, int &A) +{ + if(N == 0) { + A = 1; + return 1; + } + if(N < 10) { + A = N; + return N; + } + + int res1 = 9*dfs((N/10)-1, A); + int res2 = (N%10)*dfs(N/10, A); + + if(res1 >= res2) { + A = A*10 + 9; + } + else { + A = A*10 + (N%10); + } + + std::cout << A << std::endl; + + return std::max(res1, res2); +} +*/ +/* +int solve(int n) +{ + if(n == 0) return 1; + else if(n < 10) return n; + else return std::max(solve(n/10)*(n%10), solve(n/10-1)*9); +} + +std::vector res; + +std::vector restoreIpAddresses(std::string s) +{ + std::string path; + + dfs(s, 0, 0, path); + + return res; +} + +void dfs(std::string s, int count, int pos, std::string path) +{ + if(count > 4) return; + if(pos == s.size() && count == 4) { + path.pop_back(); + res.push_back(path); + return; + } + + for(int i = 1; i <= 3 && pos + i <= s.size(); i++) + { + std::string tmp = s.substr(pos, i); + if(tmp[0] == '0' && i > 1) return; + else if(std::stoi(tmp) <= 255) { + dfs(s, count + 1, pos + i, path + tmp + ".", res); + } + } + +} + + +int longestStrChain(std::vector &words) +{ + sort(words.begin(), words.end(), [](std::string str1, std::string str2){ + return str1.size() < str2.size(); + }); + + std::unordered_map hash; + + int res = 0; + + for(const auto &word : words) { + for(int i = 0; i < word.size(); i++) { + std::string pre = word.substr(0,i) + word.substr(i + 1); + hash[word] = std::max(hash[word], hash.count(pre) ? hash[pre] + 1 : 1); + } + res = std::max(res, hash[word]); + } + + return res; +} +*/ + + + + + +/* +int data[2000]; +int tail; +int head; +int pop(int *d); +int push(int d); + +void initQueue() { + head = tail = 0; +} + +bool ifFull() { + if((tail+1)%head == 2000) { + return true; + } + return false; +} + +bool isEmpty() { + if(head == tail) { + return true; + } + return false; +} + +int pop(int *d) +{ + if(isEmpty()) return -1; + *d = data[head]; + head = (head+1)%2000; +} + +int push(int d) +{ + if(isFull()) return -1; + data[tail] = d; + tail = (tail+1)%2000; +} +*/ +/* + +class MyCircularQueue +{ + int *data; + int front, tail; + int size; + +public: + MyCircularQueue(int k) : data(new int[k+1]) { + memset(data, 0, sizeof(data)); + front = tail = 0; + size = k+1; + } + + bool enQueue(int value) { + if(isFull()) return false; + data[tail] = value; + tail = (tail + 1)%size; + return true; + } + + bool deQueue() { + if(isEmpty()) return false; + front = (front + 1)%size; + return true; + } + + int Front() { + if(isEmpty()) return -1; + return data[front]; + } + + int Rear() { + if(isEmpty()) return -1; + return data[(size+tail-1)%size]; + } + + bool isEmpty() { + if(front == tail) return true; + return false; + } + + bool isFull() { + if((tail+1)%size == front) return true; + return false; + } + +}; + +int randNum(); +int getNumber() ; + +void reverseStr(std::string &str); +void reverse(char *pBegin, char *pEnd); +void reverseStr(char *pStr); +std::string KeepKChar(std::string str, int k) +{ + if(k <= 0 || str.size() < k) return str; + + k = str.size() - k; + + std::string res; + + for(int i = 0; i < str.size(); i++) + { + while(!res.empty() && str[i] < res.back() && k) + { + res.pop_back(); + k--; + } + + res.push_back(str[i]); + } + + return res; +} + +#define DEBUG 1 + +#ifdef DEBUG + #define WHILE(x) write(__FILE__,__LINE__); while(x) +#else + #define WHILE(x) while(x) +#endif + +int main() { + + // std::string str = "bcade"; + // int k = 3; + + // std::cout << KeepKChar(str, k) << std::endl; + + // char str[] = "hello world I am a student"; + // char str[] = "hello "; + // std::vector nums = {1,2,3}; + // // nums.reserve(100); + // std::vector(nums).swap(nums); + + // std::cout << sizeof(nums) << std::endl; + + // std::string str = "hello"; + + // std::string str = "123456"; + + // for(int i = 0; i <= str.size()+2; i++) { + // std::cout << str[i] - '0' << std::endl; + // } + + // std::cout << str[8] << std::endl; + + // reverseStr(str); + + // std::cout << str << std::endl; + // printf("%s\n", str); + + // int num = 0; + + // int n = !num; + + // std::cout << n << std::endl; + + // while(1) + // #ifdef DEBUG + // #define WHILE(x) writes(__FILE__,__LINE__); while(x) + // #else + // #define WHILE(x) while(x) + // #endif + WHILE(1) + { + std::cout << "is" << std::endl; + } + + return 0; +} + +//等概率生成一个[1~600]之间的数 +int randNum() +{ + int num; + while(1) + { num = rand()%65536; + if(num > 59999) continue; + else break; + } + + return num%600 + 1; +} + +//等概率生成一个[1~30W]之间的数 +int getNumber() +{ + int num; + while(1) + { + num = 600*(randNum()-1) + randNum(); + if(num > 300000) continue; + else break; + } + + return num; +} + +int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) +{ + int s1 = (C-A)*(D-B), s2 = (G-E)*(H-F); + + if(C <= E || A >= G || B >= F || D <= H) return s1 + s2; + + int s = (std::min(C,G) - std::max(A,E)) * (std::min(D, H) - std::max(B, F)); + + return s1 + s2 - s; +} + +void nextPermutation(std::vector &nums) +{ + int i = nums.size() - 2; + for(; i >= 0; i--) { + if(nums[i] < nums[i+1]) break; + } + + if(i == -1) { + reverse(nums.begin(), nums.end()); + return; + } + + int j = nums.size() -1; + for(; j > i; j--) { + if(nums[j] > nums[i]) break; + } + + std::swap(nums[i], nums[j]); + + reverse(nums.begin() + i + 1, nums.end()); +} + + +void reverseStr(std::string &str) +{ + if(str.empty()) return; + + int i = 0, j = 0; + while(i <= str.size()) + { + if((i < str.size() && str[i] == ' ') || i == str.size()) { + reverse(str.begin() + j, str.begin() + i); + j = i + 1; + } + i++; + } + + reverse(str.begin(), str.end()); +} + + + +void reverseStr(char *pStr) +{ + char *pBegin = pStr, *pEnd = pStr; + + //先翻转单个单词 + while(*pBegin != '\0') + { + if(*pEnd == ' ' || *pEnd == '\0') { + reverse(pBegin, --pEnd); + pBegin = ++pEnd; + } + + if(*pBegin == ' ') { + pBegin++; + pEnd++; + } + else if(*pEnd != '\0') + pEnd++; + } + + pBegin = pStr, pEnd = pStr; + + while(*pEnd != '\0') { + pEnd++; + } + + reverse(pBegin, --pEnd); +} + +void reverse(char *pBegin, char *pEnd) +{ + if(pBegin == nullptr || pEnd == nullptr) return; + + while(pBegin < pEnd) + { + char ch = *pBegin; + *pBegin = *pEnd; + *pEnd = ch; + pBegin++; + pEnd--; + } +} + +std::vector findAndReplacePattern(std::vector &words, std::string pattern) +{ + std::vector res; + + std::string P = F(pattern); + + for(auto &word : word) + { + if(F(word) == P) { + res.push_back(word); + } + } + + return res; +} + +std::string F(std::string word) +{ + std::unordered_map hash; + + //序列化,记录该字符前面有多少个不同字符就行 + for(const char &c : word) { + if(!hash.count(c)) hash[c] = hash.size(); + } + + for(int i = 0; i < word.size(); i++) { + word[i] = 'a' + hash[word[i]]; + } + + return word; +} +*/ + + +/* +int numsSubarrayWithSum(std::vector &A, int S) +{ + int sum = 0, count = 0; + std::unordered_map hash; + hash[0] = 1; + + for(int i = 0; i < A.size(); i++) + { + sum += A[i]; + count += hash[sum-S]; + hash[sum]++; + } + + return count; +} +*/ +/* +void dfs(std::vector &matrix, std::vector &row, std::vector &col, std::vector &rightDiag, std::vector &leftDiag, int i); + +// std::vector res; +std::vector> res; + +std::vector> solveNQeens(int n) +{ + std::vector row(n, 0), col(n, 0), rightDiag(2*n-1, 0), leftDiag(2*n-1, 0); + + std::vector matrix(n, std::string(n, '.')); + + dfs(matrix, row, col, rightDiag, leftDiag, 0); + + return res; +} + +void dfs(std::vector &matrix, std::vector &row, std::vector &col, std::vector &rightDiag, std::vector &leftDiag, int i) +{ + int n = matrix.size(); + + if(i == n) { + res.push_back(matrix); + return; + } + + for(int j = 0; j < n; j++) + { + if(!row[j] && !col[j] && !leftDiag[i+j] && !rightDiag[i+n-1-j]) + { + matrix[i][j] = 'Q'; + row[j] = col[j] = leftDiag[i+j] = rightDiag[i+n-1-j] = 1; + + dfs(matrix, row, col, rightDiag, leftDiag, i + 1); + + matrix[i][j] = '.'; + row[j] = col[j] = leftDiag[i+j] = rightDiag[i+n-1-j] = 0; + } + + } + +} + +int main() { + // std::shared_ptr sp1 = std::make_shared(2); + // std::shared_ptr sp2 = sp1; + + // sp1.reset(); + + // // std::cout << *sp1 << std::endl; + + // std::cout << sp1.use_count() << std::endl; + + // std::vector nums; + // nums.push_back(1); + + solveNQeens(4); + + for(int i = 0; i < res.size(); i++) { + for(int j = 0; j < res[i].size(); j++) { + std::cout << res[i][j] << " "; + } + std::cout << std::endl; + } + + return 0; +} + + +std::vector> row(9, std::vector(9, 0)), col(9, std::vector(9,0)), block(9, std::vector(9, 0)); + +bool find = false; + +void solveSudoku(std::vector> &board) +{ + //先把数逐个填入row,col,block,方便确定下面填充哪些数 + + int m = board.size(), n = board[0].size(); + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { + if(board[i][j] != '.') { + int k = (i/3)*3 + j/3; + int n = board[i][j] - '1'; + row[i][n] = col[j][n] = block[k][n] = 1 + } + } + } + + dfs(board, 0, 0); + + +} + +void dfs(std::vector> &board, int i, int j) +{ + if(find) { + return; + } + + if(i == 9) { + find = true; + return; + } + + if(j == 9) { + dfs(board, i + 1, 0); + return; + } + + if(board[i][j] != '.') { + dfs(board, i, j+1); + } + else + { + int m = board.size(), n = board[0].size(); + + for(int n = 0; n < 9; n++) + { + int k = (i/3)*3 + j/3; + if(!row[i][n] && !col[j][n] && !block[k][n]) + { + row[i][n] = col[j][n] = block[k][n] = 1; + board[i][j] = n + '1'; + + dfs(board, i, j+1); + if(find) return; + + row[i][n] = col[j][n] = block[k][n] = 0; + board[i][j] = '.'; + } + } + + } + +} + +*/ + +/* +class MyVector +{ +private: + int *data; //实际存放元素的数组 + int capacity; //容量 + int size; //数组大小 + + void addsize(int newsize) //动态扩容函数 + { + int *newData = new int[newsize]; + for(int i = 0; i < size; i++) { + newData[i] = data[i]; + } + delete[] data; + + data = newData; + capacity = newsize; //扩容时容量增加但是size不增加,size代表的是数组元素个数 + } + +public: + MyVector() : data(nullptr), capacity(0), size(0) { + + } + + ~MyVector() { + delete[] data; + } + + MyVector(int m_size, int val) { + data = new int[m_size]; + memset(data, val, sizeof(data)); + capacity = m_size; + size = m_size; + } + + void push_back(int val) + { + if(capacity == size) { + addsize(2*size); //两倍扩容 + } + data[size++] = val; + } + + void pop_back() { + if(size != 0) { + size--; + } + } + + int getsize() { + return size; + } + + int &operator[] (int i) { + return data[i]; + } + +}; + +int main() { + + MyVector vector(3, 0); + vector.pop_back(); + vector.pop_back(); + vector.pop_back(); + + std::cout << vector.getsize() << std::endl; + + // MyVector num; + // std::vector nums(100, 0); + // nums.pop_back(); + // std::vector nums(5, 1); + // nums.resize(3,0); + + // for(int i = 0; i < nums.size(); i++) { + // std::cout << nums[i] << " "; + // } + // std::cout << std::endl; + + // std::cout << nums.size() << " " << nums.capacity() << std::endl; + + return 0; +} + + +int coinChange(std::vector &coins, int amount) +{ + int n = coins.size(); + std::vector> dp(n + 1, std::vector(amount + 1, amount + 1)); + for(int i = 0; i < n; i++) { + dp[i][0] = 0; + } + + for(int i = 1; i <= n; i++) { + for(int j = 1; j <= amount; j++) { + if(j >= coins[i-1]) { + dp[i][j] = std::min(dp[i-1][j], dp[i][j-coins[i-1]] + 1); + } + else { + dp[i][j] = dp[i-1][j]; + } + } + } + + return dp[n][amount] == amount + 1 ? -1 : dp[n][amount]; +} + + +bool Isomorphic(TreeNode *root1, TreeNode *root2) +{ + if(root1 == nullptr || root2 == nullptr) return root1 == root2; + + if(root1->val != root2->val) return false; + + if(root1->left == nullptr && root2->left == nullptr) { + return Isomorphic(root1->right, root2->right); + } + else if(root1->right == nullptr && root2->right == nullptr) { + return Isomorphic(root1->left, root2->left); + } + else if(root1->left && root2->left && root1->left->val == root2->left->val) { + return Isomorphic(root1->left, root2->left) && Isomorphic(root1->right, root2->right); + } + else { + return Isomorphic(root1->right, root2->left) && Isomorphic(root1->left, root2->right); + } + +} + +bool findNode(TreeNode *root, TreeNode *pFind) +{ + if(root == nullptr) return false; + + if(root == pFind) return true; + + if(root->val < pFind->val) { + return findNode(root->right, pFind); + } + else { + return findNode(root->left, pFind); + } + +} + + +int evalRPN(std::vector &tokens) +{ + std::stack sta; + + for(int i = 0; i < tokens.size(); i++) + { + std::string str = tokens[i]; + + if(str == '+') { + int second = sta.top(); sta.pop(); + int first = sta.top(); sta.pop(); + sta.push(first+second); + } + else if(str == "-") { + int second = sta.top(); sta.pop(); + int first = sta.top(); sta.pop(); + sta.push(first-second); + } + else if(str == "*") { + int second = sta.top(); sta.pop(); + int first = sta.top(); sta.pop(); + sta.push(first*second); + } + else if(str == "/") { + int second = sta.top(); sta.pop(); + int first = sta.top(); sta.pop(); + sta.push(first/second); + } + else { + sta.push(stoi(str)); + } + } + + return sta.top(); +} + + +int evalRPN(std::vector &tokens) +{ + std::stack sta; + + for(int i = 0; i < tokens.size(); i++) + { + if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") + { + int second = sta.top(); sta.pop(); + int first = sta.top(); sta.pop(); + sta.push(applyOp(first, second, tokens[i])); + } + else { + sta.push(stoi(tokens[i])); + } + } + + return sta.top(); +} + +int applyOp(int first, int second, std::string op) +{ + int res; + switch(op[0]) { + case '+' : res = first + second; break; + case '-' : res = first - second; break; + case '*' : res = first * second; break; + case '/' : res = first / second; break; + } + + return res; +} + +int calculate(std::string s) +{ + int result = 0; + int number = 0; + int sign = 1; + + std::stack sta; + + for(int i = 0; i < s.size(); i++) + { + if(isdigit(s[i])) { + number = number*10 + (s[i] - '0'); + } + else if(s[i] == '+') { + result += sign*number; + number = 0; + sign = 1; + } + else if(s[i] == '-') { + result += sign*number; + number = 0; + sign = -1; + } + else if(s[i] == '(') { + sta.push(result); + sta.push(sign); + result = 0 + sign = 1; + } + else if(s[i] == ')') { + result += sign*number; + number = 0; + result *= sta.top(); + result += sta.top(); + } + } + + if(number != 0) return result += sign*number; + + return result; +} +*/ + + + +/* +int maxProduct(std::vector &words) +{ + int n = words.size(); + int res = 0; + + for(int i = 0; i < n ;i++) + { + int count = 0; + int size = words[i].size(); + for(const char &c : words[i]) { + count |= (1 << (c-'a')); + } + + for(int j = i+1; j < n; j++) { + int tmp = 0; + for(const char &c : words[j]) { + tmp |= (1 << (c-'a')); + } + + if((count & tmp) == 0) { + res = std::max(res, (int)(size*words[j].size())); + } + } + } + + return res; +} + +int maximumUniqueSubarray(std::vector &nums) +{ + std::unordered_map hash; + + int sum = 0, res = 0; + + int j = 0, i = 0; + while(j < nums.size()) + { + while(hash.count(nums[j])) { + sum -= nums[i]; + if(--hash[nums[i]] == 0) { + hash.erase(nums[i]); + } + i++; + } + + sum += nums[j]; + res = std::max(res, sum); + hash[nums[j++]]++; + } + + return res; +} + + +int maximumUniqueSubarray(std::vector &nums) +{ + std::unordered_set mySet; + + int sum = 0, res = 0; + + int i = 0, j = 0; + while(j < nums.size()) + { + while(mySet.count(nums[j])) { + sum -= nums[i]; + mySet.erase(nums[i++]); + } + + sum += nums[j]; + res = std::max(res, sum); + mySet.insert(nums[j++]); + } + + return res; +} + +int Get_0_1() { + + while(1) + { + int first = rand(), second = rand(); + + if(first == 0 && second == 1) { + return 1; + } + else if(first == 1 && second == 0) { + return 0; + } + } + + return -1; +} + +std::vector findDuplicate(std::vector &nums) +{ + std::vector res; + + for(int i = 0; i < nums.size(); i++) + { + int index = abs(nums[i]) - 1; + if(nums[index] < 0) { + res.push_back(abs(nums[i])); + } + else { + nums[index] *= (-1); + } + } + + return res; +} + + +int maximumGap(std::vector &nums) +{ + if(nums.size() < 2) return 0; + + sort(nums.begin(), nums.end()); + + int diff = INT_MIN; + for(int i = 1; i < nums.size(); i++) { + diff = std::max(diff, nums[i] - nums[i-1]); + } + + return diff; +} +*/ + + + +/* + +int maximumGap(std::vector &nums) +{ + if(nums.size() < 2) return 0; + + int minVal = INT_MAX, maxVal = INT_MIN; + for(const int &n : nums) { + minVal = std::min(minVal, n); + maxVal = std::max(maxVal, n); + } + + int n = nums.size(); + int bucketNum = (maxVal - minVal)/n + 1; + + if(maxVal == minVal) return 0; //表明所有元素都相等 + + //记录桶中是否存在元素以及桶中每个元素的最大和最小值 + std::vector hasNum(bucketNum, 0); + std::vector mins(bucketNum), maxs(bucketNum); + + for(int i = 0; i < n; i++) + { + //计算桶编号 + int num = (nums[i] - minVal)/n; + mins[num] = hasNum[num] ? std::min(mins[num], nums[i]) : nums[i]; + maxs[num] = hasNum[num] ? std::max(maxs[num], nums[i]) : nums[i]; + hasNum[num] = 1; + } + + //计算前一个桶的最大值和后一个桶的最小值之差就是最大的diff.不用管桶内数据,因为桶内的数据差肯定要比桶外的数据差小 + int diff = maxs[0] - mins[0]; //防止只有一个桶 + int preMax = maxs[0]; + for(int i = 1; i < bucketNum; i++) { + if(hasNum[i]) { + diff = std::max(diff, mins[i] - preMax); + preMax = maxs[i]; + } + } + + return diff; +} + +int climbStairs(int n) +{ + if(n == 1) return 1; + + std::vector dp(n+1); + + dp[1] = 1, dp[2] = 2; + for(int i = 3; i <= n; i++) { + dp[i] = dp[i-1] + dp[i-2]; + } + + return dp[n]; +} + +int climbStairs(int n) +{ + if(n == 1) return 1; + + int first = 1, second = 2; + + int cur = second; + + for(int i = 3; i <= n; i++) { + cur = first + second; + first = second; + second = cur; + } + + return cur; +} + + +int rob(std::vector &nums) +{ + if(nums.size() == 1) return nums[0]; + + std::vector dp(nums.size(), 0); + + dp[0] = nums[0], dp[1] = std::max(nums[0], nums[1]); + + for(int i = 2; i < nums.size(); i++) { + dp[i] = std::max(dp[i-2] + nums[i], dp[i-1]); + } + + return dp[nums.size()-1]; +} + +int rob(std::vector &nums, int left, int right) +{ + int first = nums[left], second = std::max(nums[left], nums[left+1]); + int cur = second; + + for(int i = left + 2; i <= right; i++) { + cur = std::max(first + nums[i], second); + first = second; + second = cur; + } + + return cur; +} + +int rob(std::vector &nums) +{ + if(nums.size() == 1) return nums[0]; + if(nums.size() == 2) return std::max(nums[0], nums[1]); + + return std::max(rob(nums, 0, nums.size()-2), rob(nums, 1, nums.size()-1)); +} + +std::unordered_map hash; + +int rob(TreeNode *root) +{ + if(root == nullptr) return 0; + + int money1 = root->val; + + if(root->left) { + money1 += rob(root->left->left) + rob(root->left->right); + } + if(rob->right) { + money1 += rob(root->right->left) + rob(root->right->right); + } + + int money2 = rob(root->left) + rob(root->right); + + hash[root] = std::max(money1, money2); + + return std::max(money1, money2); +} + +int numberOfArithmeticsSlices(std::vector &nums) +{ + if(nums.size() < 3) return 0; + + std::vector dp(nums.size(), 0); + + for(int i = 2 ; i < nums.size(); i++) { + if((nums[i] - nums[i-1]) == (nums[i-1] - nums[i-2])) { + dp[i] = dp[i-1] + 1; + } + } + + return accumulate(dp.begin(), dp.end(), 0); +} + + +ListNode* removeNthFromEnd(ListNode *head, int n) +{ + if(head == nullptr) return head; + + ListNode *base = new ListNode(-1); + base->next = head; + + ListNode *fast = base, *slow = fast; + + for(int i = 0; i < n; i++) { + fast = fast->next; + if(fast == nullptr) break; + } + + if(fast == nullptr) return head; + + while(fast->next) { + fast = fast->next; + slow = slow->next; + } + + slow->next = slow->next->next; + + return base->next; +} + +int myAtoi(std::string s) +{ + int res = 0; + + int i = 0; + while(s[i] == ' ') i++; + + bool minus = false; + if(s[i] == '+') { + i++; + } + else if(s[i] == '-') { + minus = true; + i++; + } + + int flag = minus ? -1 : 1; + for(; i < s.size(); i++) + { + if(!isdigit(s[i])) break; + + if(res > INT_MAX/10 || (res == INT_MAX/10 && (s[i]-'0') > 7)) { + res = INT_MAX; + break; + } + else if(res < INT_MIN/10 || (res == INT_MIN/10 && (s[i]-'0') > 8)) { + res = INT_MIN; + break; + } + + res = res*10 + flag*(s[i]-'0'); + } + + return res; +} + +*/ +/* +void quickSort(std::vector &nums, int left, int right); +int partition(std::vector &nums, int left, int right); + +int main() { + std::vector nums = {5,4,2,6,1}; + + quickSort(nums, 0, nums.size() - 1); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + +void quickSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = partition(nums, left, right); + quickSort(nums, left, mid); + quickSort(nums, mid + 1, right); + } + +} + +int partition(std::vector &nums, int left, int right) +{ + int pivot = nums[left]; + + while(left < right) + { + while(left < right && nums[right] >= pivot) right--; + std::swap(nums[left], nums[right]); + + while(left < right && nums[left] <= pivot) left++; + std::swap(nums[left], nums[right]); + } + + return left; +} + +int findKthLargest(std::vector &nums, int k) +{ + if(nums.size() < k || k <= 0) return -1; + + int left = 0, right = nums.size() - 1; + + k = nums.size() - k; + + while(left <= right) + { + int index = partition(nums, left, right); + + if(index == k) return nums[k]; + else if(index < k) { + left = index + 1; + } + else if(index > k) { + right = index - 1; + } + } + + return -1; +} + + + +int findKthLargest(std::vector &nums, int k) +{ + std::priority_queue, std::greater> pq; + + for(const int &n : nums) { + pq.push(n); + if(pq.size() > k) pq.pop(); + } + + return pq.top(); + +} + +*/ + +/* +class Foo +{ +public: + Foo() = default; + explicit Foo(int a) { + std::cout << "Explicit Foo(int a)" << std::endl; + } + +}; + + +void bubbleSort(std::vector &nums) +{ + int n = nums.size(); + + for(int i = 0; i < n; i++) { + for(int j = n-2; j >= i; j--) { + if(nums[j] > nums[j+1]) { + std::swap(nums[j], nums[j+1]); + } + } + } + +} + +int max(int a, int b) +{ + return a > b ? a : b; +} + +void printMax(int(*p)(int, int) ,int a, int b) +{ + std::cout << (*p)(a,b) << std::endl; +} + +void bubbleSort(std::vector &nums); + + + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + +public: + static Singleton& getInstance() { + static Singleton demo; + return demo; + } + + void print() { + std::cout << "Do something~" << std::endl; + } + +}; + +std::string::size_type find_char(const std::string &s, char c, std::string::size_type &occurs, ...); + +int main() { + std::string s = "hello world"; + + // unsigned long num; + std::string::size_type num; + + std::cout << find_char(s, 'l', num) << std::endl; + + std::cout << num << std::endl; + + return 0; +} + + +std::string::size_type find_char(const std::string &s, char c, std::string::size_type &occurs, ...) +{ + auto res = s.size(); + occurs = 0; + + for(decltype(res) i = 0; i != s.size(); i++) + { + if(s[i] == c) { + if(res == s.size()) res = i; + ++occurs; + } + } + + return res; +} + +void sortAges(std::vector &ages) +{ + int n = ages.size(); + + std::vector timesOfAge(100, 0); + + for(int i = 0; i < n; i++) { + timesOfAge[ages[i]]++; + } + + int index = 0; + for(int i = 0; i < 100; i++) { + for(int j = 0; j < timesOfAge[i]; j++) { + ages[index++] = i; + } + } + +} + + +const int N = (int)pow(10,9) + 7; + +int maxArea(int h, int w, std::vector &horizontalCuts, std::vector &vecticalCuts) +{ + std::vector heights, widths; + heights.reverse(horizontalCuts.size() + 1); + widths.reverse(vecticalCuts.size() + 1); + + for(int i = 0; i < horizontalCuts.size(); i++) { + if(i == 0) heights.push_back(horizontalCuts[i]); + else heights.push_back(horizontalCuts[i] - horizontalCuts[i-1]); + } + heights.push_back(h - horizontalCuts.back()); + + for(int i = 0; i < vecticalCuts.size(); i++) { + if(i == 0) widths.push_back(vecticalCuts[i]); + else widths.push_back(vecticalCuts[i] - vecticalCuts[i-1]); + } + widths.push_back(w - vecticalCuts.back()); + + long maxHeight = LONG_MIN; + for(int i = 0; i < heights.size(); i++) { + maxHeight = std::max(maxHeight, heights[i]); + } + + long maxWidth = LONG_MIN; + for(int i = 0; i < widths.size(); i++) { + maxWidth = std::max(maxWidth, widths[i]); + } + + return maxWidth*maxHeight%N; +} + + +const std::string &shortestString(const std::string &s1, const std::string &s2) +{ + return s1.size() > s2.size() ? s2 : s1; +} + +std::string &shortestString(std::string &s1, std::string &s2) +{ + auto &r = shortestString(const_cast(s1), const_cast(s2)); + + return const_cast(r); +} + +void reverseString(std::vector &s) +{ + int n = s.size(); + for(int i = 0; i < n/2; i++) { + std::swap(s[i], s[n-1-i]); + } + +} + + + +int GetSteps(int n, int k) +{ + if(n == 0) return -1; + + std::vector> dp(k+1, std::vector(n, 0)); + dp[0][0] = 1; //0步到达0点只有一种方法 + + for(int i = 1; i <= k; i++) { + for(int j = 0; j < n; j++) { + dp[i][j] = dp[i-1][(j-1+n)%n] + dp[i-1][(j+1)%n]; + } + } + + return dp[k][0]; +} +int slidingPuzzle(std::vector> &board); +std::string swapChar(std::string cur, int i, int j); +int GetSteps(int n, int k); + +int main() { + int n = 2, k = 2; + + // std::cout << GetSteps(n, k) << std::endl; + + return 0; +} + +//Leetcode第773题 : 2X3滑动谜题 + +//思路:BFS +//相当于寻找字符串到指定字符串的交换次数,广度优先搜索记录搜索的层数就行 + +int slidingPuzzle(std::vector> &board) +{ + std::string target = "123450"; + std::string start = ""; + + for(int i = 0; i < board.size(); i++) { + for(int j = 0; j < board[i].size(); j++) { + start += std::to_string(board[i][j]); + } + } + + std::unordered_set mySet; //记录已经被遍历过的字符串组合 + + std::vector> direction = {{1,3}, {0,2,4}, {1,5}, {0,4}, {1,3,5}, {2,4}}; + + std::queue que; + + que.push(start); + mySet.insert(start); + + int res = 0; + + while(!que.empty()) + { + int size = que.size(); + for(int i = 0; i < size; i++) + { + std::string cur = que.front(); que.pop(); + + if(cur == target) return res; + + int zero = cur.find('0'); + + for(int dir : direction[zero]) { + std::string next = swapChar(cur, zero, dir); + if(mySet.count(next)) continue; + + mySet.insert(next); + que.push(next); + } + } + + res++; + } + + return -1; +} + + +std::string swapChar(std::string cur, int i, int j) +{ + std::swap(cur[i], cur[j]); + + return cur; +} + + +void merge(std::vector &nums1, int m, std::vector &nums2, int n) +{ + int i = m -1, j = n-1; + int k = m + n - 1; + + while(i >= 0 && j >= 0) + { + if(nums1[i] > nums2[j]) { + nums1[k--] = nums1[i--]; + } + else { + nums1[k--] = nums2[j--]; + } + } + + while(j >= 0) + { + nums1[k--] = nums2[j--]; + } + +} + +std::vector spiralOrder(std::vector> &matrix) +{ + int m = matrix.size(), n = matrix[0].size(); + + int left = 0, right = n - 1; + int up = 0, down = m - 1; + + std::vector res; + + while(res.size() < m*n) + { + for(int j = left; j <= right && res.size() < m*n; j++; ) { + res.push_back(matrix[left][j]); + } + + for(int i = up + 1; i < down && res.size() < m*n; i++;) { + res.push_back(matrix[i][right]); + } + + for(int j = right; j >= left && res.size() < m*n; j--) { + res.push_back(matrix[down][j]); + } + + for(int i = down - 1; i > up && res.size() < m*n; i--) { + res.push_back(matrix[i][left]); + } + + left++, right--; + up++, down--; + } + + return res; +} + +int i = 0; + +void test() +{ + int num = 100; + for(int n = 0; n < num; n++) i = i + 1; +} + +/* +void merge(std::vector &nums, int left, int mid, int right); + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right - left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, mid, right); + } + +} + +void merge(std::vector &nums, int left, int mid, int right) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right - left + 1]; + int teamIndex = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] < nums[rindex]) { + team[teamIndex++] = nums[lindex++]; + } + else { + team[teamIndex++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + team[teamIndex++] = nums[lindex++]; + } + + while(rindex <= right) { + team[teamIndex++] = nums[rindex++]; + } + + for(int i = 0; i < teamIndex; i++) { + nums[left+i] = team[i]; //注意left一定要加上 + } + + delete[] team; + +} + + +int reversePairs(std::vector &nums); +int mergeSort(std::vector &nums, int left, int right); + + +int main(void) { + std::vector nums = {1,3,2,3,1}; + + std::cout << reversePairs(nums) << std::endl; + + return 0; +} + + +//计算逆序对(归并排序) + +int reversePairs(std::vector &nums) +{ + return mergeSort(nums, 0, nums.size() - 1); +} + +int mergeSort(std::vector &nums, int left, int right) +{ + if(left >= right) return 0; + + int mid = left + ((right - left) >> 1); + + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + + std::vector tmp(right - left + 1); + int index = 0; + + int lindex = left, rindex = mid + 1; + + while(lindex <= mid && rindex <= right) //这和剑指上的思路不同,这是从左往右合并判断 + { + if(nums[lindex] <= nums[rindex]) { //注意:这是小于等于 + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + else { + tmp[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + + while(rindex <= right) { + tmp[index++] = nums[rindex++]; + } + + for(int i = 0; i < index; i++) { + nums[left + i] = tmp[i]; + } + + return count; +} + +ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) +{ + ListNode *curA = headA, curB = headB; + + while(curA != curB) + { + // curA = curA->next ? curA->next : headB; + // curB = curB->next ? curB->next : headA; + curA = curA ? curA->next : headB; + curB = curB ? curB->next : headA; + } + + return curA; +} + + + + + + +class String +{ +private: + char *pStr; + unsigned int size; + +public: + String(const char* str = NULL) { + if(str == NULL) { + pStr = new char[1]; + *pStr = '\0'; + size = 0; + } + else { + int len = strlen(str); + pStr = new char[len + 1]; + strcpy(pStr, str); + size = len; + } + } + + ~String() { + delete [] pStr; + } + + String(const String &s) { + int len = s.size; + pStr = new char[len + 1]; + strcpy(pStr, s.pStr); + size = len; + } + + String& operator=(const String &s) { + if(this != &s) + { + delete[] pStr; + int len = s.size; + pStr = new char[len + 1]; + strcpy(pStr, s.pStr); + size = len; + } + + return *this; + } + + int getSize() { + return this->size; + } + +}; + + +int JudgeSystem(); + +int main() { + // shared_ptr p1(new int(10)); + // shared_ptr p2 = p1; + // std::cout << p1.use_count() << std::endl; + // std::cout << p1.use_count() << std::endl; + + std::cout << JudgeSystem() << std::endl; + + return 0; +} + +int JudgeSystem() +{ + union Test { + int x; + char c; + }; + + Test demo; + demo.x = 1; + + return demo.c; +} + + +template +class shared_ptr +{ +private: + T *ptr; + int *count; + +public: + shared_ptr(T *pointer = nullptr) + { + ptr = pointer; + + if(ptr == nullptr) { + count = new int(0); + } + else { + count = new int(1); + } + } + + shared_ptr(const shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + count = smartPtr.count; + + (*count)++; + } + + shared_ptr& operator=(const shared_ptr &smartPtr) + { + if(ptr != smartPtr.ptr) + { + if(ptr != nullptr) + { + (*count)--; + if(*count == 0) { + delete ptr; + delete count; + } + } + + ptr = smartPtr.ptr; + count = smartPtr.count; + (*count)++; + } + + return *this; + } + + T& operator*() { + if(ptr != nullptr) { + return *ptr; + } + } + + T& operator->() { + if(ptr != nullptr) { + return ptr; + } + } + + ~shared_ptr() + { + if(ptr == nullptr) { + delete count; + } + else if(--(*count) == 0) { + delete ptr; + delete count; + } + } + + int use_count() { + return *count; + } + +}; + + + + +int strcmp(const char *str1, const char* str2); + +int main() { + // char str1[1] = {1}; + // char str2[1] = {255}; + // char *str1 = 1, *str2 = 255; + // char str1[5] = "bcd", str2[5] = "abaf"; + + // std::cout << strcmp(str1, str2) << std::endl; + + char c = -2; + + // std::cout << (unsigned char)c << std::endl; + printf("%d\n", (unsigned char)c); + + return 0; +} + +int strcmp(const char *str1, const char* str2) +{ + int res = 0; + + // while(!(res = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1) + // { + // str1++; + // str2++; + // } + + while(!(res = *str1 - *str2) && *str1) { + str1++; + str2++; + } + + if(res > 0) return 1; + else if(res < 0) return -1; + + return 0; +} + + +#include + +std::mutex mtx; +std::condition_variable cv; +int ready = 0; + +void printString_1() +{ + std::unique_lock lk(mtx); + + int cnt = 0; + while(cnt < 10) + { + while(ready != 0) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "A" << std::endl; + + ready = 1; + cnt++; + cv.notify_all(); + } +} + +void printString_2() +{ + std::unique_lock lk(mtx); + + int cnt = 0; + while(cnt < 10) + { + while(ready != 1) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "B" << std::endl; + + ready = 2; + cnt++; + cv.notify_all(); + } +} + +void printString_3() +{ + std::unique_lock lk(mtx); + + int cnt = 0; + while(cnt < 10) + { + while(ready != 2) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "C" << std::endl; + + ready = 0; + cnt++; + cv.notify_all(); + } +} + +int maxResult(std::vector &nums, int k); + + +int main() { + std::vector nums = {1,-5,-20,4,-1,3,-6,-3}; + int k = 2; + + std::cout << maxResult(nums, k) << std::endl; + + return 0; +} + +int maxResult(std::vector &nums, int k) +{ + int i = 0; + + int res = nums[0]; + + while(i < nums.size() - 1) + { + int maxVal = nums[i+1]; + int maxIndex = i + 1; + + int j = i + 2; + for(; j <= std::min(i + k, (int)(nums.size() - 1)); j++) + { + if(maxVal < nums[j]) { + maxVal = nums[j]; + maxIndex = j; + } + else if(maxVal == nums[j] && maxVal < 0) { + maxVal = nums[j]; + maxIndex = j; + } + } + + res += nums[maxIndex]; + + // std::cout << res << std::endl; + + i = maxIndex; + + // std::cout << i << std::endl; + } + + return res; +} + +// Leetcode第1696题 : Jump Game VI +// 维持一个单调递减队列 + +int maxResult(std::vector &nums, int k) +{ + std::deque dq; + dq.push_back(0); + + for(int i = 1; i < nums.size(); i++) + { + if(dq.front() + k < i) { + dq.pop_front(); + } + + nums[i] += nums[dq.front()]; + + while(!dq.empty() && nums[i] > nums[dq.back())]) { + dq.pop_back(); + } + + dq.push_back(i); + } + + return nums[dq.back()]; +} + + +// 堆排序 +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int i = 2*start; i <= end; i *= 2) + { + if(i < end && nums[i] < nums[i+1]) i++; + + if(tmp >= nums[i]) break; + + nums[start] = nums[i]; + + start = i; + } + + nums[start] = tmp; +} + + +void heapSort(std::vector &nums) +{ + int len = nums.size() - 1; + + for(int i = len/2; i > 0; i--) { + heapAdjust(nums, i, len); + } + + for(int i = len; i > 1; i--) { + std::swap(nums[i], nums[1]); + heapAdjust(nums, 1, i - 1); + } + +} +ListNode *addTwoNumber(ListNode *l1, ListNode *l2) +{ + ListNode *head = new ListNode(-1); + ListNode *base = head; + + int carry = 0; + + while(l1 || l2 || carry) + { + carry = (l1 ? l1->val ? 0) + (l2 ? l2->val ? 0); + base->next = new ListNode(carry%10); + carry /= 10; + + base = base->next; + + if(l1) l1 = l1->next; + + if(l2) l2 = l2->next; + } + + return head->next; +} + +template +struct plus { + T operator()(const T &x, const T &y) const { + return x + y; + } +}; + +template +struct minus { + T operator()(const T &x, const T &y) const { + return x - y - z; + } +}; + + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < nums[i-1]) { + int tmp = nums[i]; + int j = i-1; + for(; j >= 0 && nums[j] > tmp; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } +} + +std::string addTwoNumber(std::string num1, std::string num2); + + +int main() { + std::string num1 = "123", num2 = "959"; + + std::cout << addTwoNumber(num1, num2) << std::endl; + + return 0; +} + + + +std::string addTwoNumber(std::string num1, std::string num2) +{ + reverse(num1.begin(), num1.end()); + reverse(num2.begin(), num2.end()); + + int carry = 0; + int i = 0, j = 0; + std::string res; + + while(i != num1.size() || j != num2.size() || carry) + { + carry += (i == num1.size() ? '0' : num1[i++]) - '0' + (j == num2.size() ? '0' : num2[j++]) - '0'; + + res += std::to_string(carry%10); + + carry /= 10; + } + + reverse(res.begin(), res.end()); + + return res; +} + +// dp[i] 代表第i的元素结尾满足条件的子数组总个数 +// if nums[i] < L, dp[i] = dp[i-1] +// if nums[i] > R, dp[i] = 0, prev = i +// if L <= nums[i] <= R, dp[i] = i - prev, + +// base case i = 0 + +int numsSubarrayBoundedMax(std::vector &nums, int left, int right) +{ + std::vector dp(nums.size(), 0); + + int prev = -1; + + if(nums[0] >= left && nums[0] <= right) dp[0] = 1; + else if(nums[0] > right) prev = 0; + + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < left && i > 0) { + dp[i] = dp[i-1]; + } + else if(nums[i] > right) { + dp[i] = 0; + prev = i; + } + else if(nums[i] >= left && nums[i] <= right) { + dp[i] = i - prev; + } + } + + return accumulate(dp.begin(), dp.end(), 0); +} + +int numsSubarrayWithSum(std::vector &nums, int left, int right) +{ + int prev = -1; + + int dp = 0; + int res = 0; + + for(int i = 0; i < nums.size(); i++) + { + if(nums[i] < left && i > 0) { + res += dp; + } + else if(nums[i] > right) { + dp = 0; + prev = i; + } + else if(nums[i] >= left && nums[i] <= right) { + dp = i - prev; + res += dp; + } + } + + return res; +} + + +#include +// #include + +const char* getText() ; + +// class A +// { +// public: +// A() { std::cout << "A" << std::endl; } +// ~A() { std::cout << "~A" << std::endl; } + +// }; + +// class B +// { +// public: +// B(A &a):_a(a) { +// std::cout << "B" << std::endl; +// } +// ~B() { +// std::cout << "~B" << std::endl; +// } + +// private: +// A _a; + +// }; + +std::string reverse(std::string str) +{ + if(str.size() <= 1) return str; + + return reverse(str.substr(1)) + str.substr(0, 1); +} + +class A { +public: + A() { + m_data = 1; + } + virtual ~A() {} + int getData() { + return m_data; + } + +private: + int m_data; + +}; + +class B : public A +{ +public: + B(){} + virtual ~B(){} + +}; + +int main() { + + // B b; + // memset(&b, 0x0, sizeof(b)); + + char *c[] = {"ENTER", "NEW", "POINT", "FIRST"}; + char **cp[] = {c + 3, c+2, c+1, c}; + char ***cpp = cp; + + printf("%s\n", **++cpp); + printf("%s\n",*--*++cpp+3); + printf("%s\n",*cpp[-2]+3); + printf("%s\n",cpp[-1][-1]+1); + + // const char* showText = getText(); + // printf("%s\n", showText); + + // A a; + // B b(a); + + // std::string str = "hello"; + + // std::cout << reverse(str) << std::endl; + + + return 0; +} + +const char* getText() +{ + const char* text = "this is the show Text"; + return text; +} + +int reversePairs(std::vector &nums) +{ + return mergeSort(nums, 0, nums.size() - 1); +} + + +int mergeSort(std::vector &nums, int left, int right) +{ + if(left >= right) return 0; + + int mid = left + ((right - left) >> 1); + + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + + std::vector tmp(right - left + 1); + int index = 0; + + int lindex = left, rindex = mid + 1; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] <= nums[rindex]) { + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + else { + tmp[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + + while(rindex <= right) { + tmp[index++] = nums[rindex++]; + } + + for(int i = 0; i < tmp.size(); i++) { + nums[left + i] = tmp[i]; + } + + return count; +} + + +int mergeSort(std::vector &nums, int left, int right) +{ + if(left >= right) return 0; + + int mid = left + ((right - left) >> 1); + + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + + std::vector tmp(right - left + 1); + int index = right - left; + + int lindex = mid, rindex = right; + + while(lindex >= left && rindex >= mid + 1) + { + if(nums[lindex] > nums[rindex]) { //从右往左计数 + count += rindex - mid; + tmp[index--] = nums[lindex--]; + } + else { + tmp[index--] = nums[rindex--]; + } + } + + while(lindex >= left) { + tmp[index--] = nums[lindex--]; + } + + while(rindex >= mid + 1) { + tmo[index--] = nums[rindex--]; + } + + for(int i = 0; i < tmp.size(); i++) { + nums[left+i] = tmp[i]; + } + + return count; +} + + + +class Base +{ +public: + Base(){ + std::cout << "I am base constructor" << std::endl; + } + virtual void print() { + std::cout << "I am base" << std::endl; + } + +private: + short val; +}; + +class Derived : public Base +{ +public: + void print() { + std::cout << "I am derived" << std::endl; + } + +}; + + +int main() { + // Base demo(1); + + // Derived d; + + // Base *pb = new Base; + // pb->print(); + // Base *pb = &d; + // pb->print(); + + // Derived *pd = &d; + // pd->print(); + + Derived d; + std::cout << sizeof(d) << std::endl; + + return 0; +} + +int numMatchingSubseq(std::string s, std::vector &words) +{ + int count = 0; + for(const auto &word : words) { + if(isMatch(word, s)) { + count++; + } + } + + return count; +} + +bool isMatch(std::string &t, std::string &p) +{ + int j = 0; + + for(int i = 0; i < p.size() && j < t.size(); i++) { + if(p[i] == t[j]) j++; + } + + return j == t.size(); +} + +int numMatchingSubseq(std::string s, std::vector &words) +{ + int count = 0; + + std::vector> index(128); + for(int i = 0; i < s.size(); i++) { + index[s[i]].push_back(i); + } + + for(const auto &word : words) + { + int j = 0, k = 0; + for(; k < word.size(); k++) { + char ch = word[k]; + if(index[ch].empty()) break; + + auto pos = lower_bound(index[ch].begin(), index[ch].end(), j); + if(pos == index[ch].end()) break; + + j = *pos + 1; + } + + if(k == word.size()) count++; + } + + return count; +} + +int numMatchingSubseq(std::string s, std::vector &words) +{ + std::vector> alpha(26); + for(int i = 0; i < s.size(); i++) { + alpha[s[i]-'a'].push_back(i); + } + + int count = 0; + + for(const auto &word : words) + { + int x = 0; + bool find = true; + + for(char &c : word) { + auto it = lower_bound(alpha[c-'a'].begin(), alpha[c-'a'].end(), x); + if(it == alpha[c-'a'].end()) { + find = false; + break; + } + x = *it + 1; + } + + if(find) count++; + } + + return count; +} + +struct Base1 { + Base1() = default; + Base1(const std::string &); + Base1(std::shared_ptr); +}; + +struct Base2 { + Base2() = default; + Base2(const std::string &); + Base2(int); +}; + +struct D1: public Base1, public Base2 { + using Base1::Base1; + using Base2::Base2; +}; + + +// int main() { + +// D1 d; + +// // int *p; +// // std::cout << sizeof(*p) << std::endl; + +// // int x[10] = {1,2,3}; +// // int *p = x; + +// // std::cout << sizeof(x)/sizeof(*x) << std::endl; +// // std::cout << sizeof(p)/sizeof(*p) << std::endl; + +// // std::cout << *p << std::endl; +// // std::cout << sizeof(*x) << std::endl; + +// return 0; +// } + + +int bfs(std::vector> &map, int i, int j); + +struct Node { + int x, y, k, step; + Node(int m_x, int m_y, int m_k, int m_step) { + x = m_x; + y = m_y; + k = m_k; + step = m_step; + } +}; + +std::vector dir = {-1, 0, 1, 0, -1}; + +int visited[105][105][1030]; + +int main() { + int M, N; + std::cin >> M >> N; + std::vector> map(M, std::vector(N)); + + for(int i = 0; i < M; i++) { + for(int j = 0; j < N; j++) { + std::cin >> map[i][j]; + } + } + + memset(visited, 0, sizeof(visited)); + + for(int i = 0; i < M; i++) { + for(int j = 0; j < N; j++) { + if(map[i][j] == '2') { + visited[i][j][0] = 1; + std::cout << bfs(map, i, j) << std::endl; + return 0; + } + } + } + + return 0; +} + + +int bfs(std::vector> &map, int i, int j) +{ + int m = map.size(), n = map[0].size(); + + std::queue que; + que.push(Node(i, j, 0, 0)); + + while(!que.empty()) + { + Node tmp = que.front(); que.pop(); + + if(map[tmp.x][tmp.y] == '3') return tmp.step; + + for(int k = 0; k < dir.size() - 1; k++) { + int x = tmp.x + dir[k], y = tmp.y + dir[k+1]; + if(x < 0 || x >= m || y < 0 || y >= n || map[x][y] == '0') continue; + + int key = tmp.k; + + if('a' <= map[x][y] && map[x][y] <= 'z') key |= (1 << (map[x][y] - 'a')); + if(('A' <= map[x][y] && map[x][y] <= 'Z') && ((key & (1 << (map[x][y] - 'A'))) == 0)) continue; // + + if(!visited[x][y][key]) { + visited[x][y][key] = 1; + que.push(Node(x, y, key, tmp.step + 1)); + } + } + } + +} + +std::string removeDuplicate(std::string s) +{ + std::string res; + + for(const char &c : s) { + if(res.empty()) { + res.push_back(c); + continue; + } + if(res.back() == c) res.pop_back(); + else res.push_back(c); + } + + return res; +} + + + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton&); + Singleton& operator=(const Singleton&); + + +public: + // static Singleton& getInstance() { + // static Singleton demo; + // return demo; + // } + static Singleton& getInstance(); + + void print() { + std::cout << "do something!" << std::endl; + } + +}; + + +Singleton& Singleton::getInstance() +{ + static Singleton demo; + return demo; +} + + +int main() { + Singleton& demo = Singleton::getInstance(); + + demo.print(); + + return 0; +} + +int findMaxConsectiveOnes(std::vector &nums) +{ + int count = 0; + + int left = 0, right = 0; + while(left < nums.size()) + { + if(nums[left] == 1) { + right = left; + while(right + 1 < nums.size() && nums[right] == nums[right+1]) right++; + count = std::max(count, right - left + 1); + left = right + 1; + } + else { + left++; + } + } + + return count; +} + + +int findMaxConsectiveOnes(std::vector &nums) +{ + int count = 0, maxLen = 0; + + for(int &n : nums) { + if(n == 1) maxLen = std::max(maxLen, ++count); + else count = 0; + } + + return maxLen; +} + + + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < nums[i-1]) { + int tmp = nums[i]; + int j = i - 1; + for(; nums[j] >= tmp && j >= 0; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } +} + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + while(gap >= 1) + { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) + { + if(nums[i] < nums[i-gap]) { + int tmp = nums[i]; + int j = i - gap; + for(; nums[j] > tmp && j >= 0; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + if(gap == 1) break; + } + +} + +int partition(std::vector &nums, int left, int right) +{ + int pivotkey = nums[left]; + + while(left < right) + { + while(left < right && nums[right] > pivotkey) right--; + std::swap(nums[left], nums[right]); + + while(left < right && nums[left] < pivotkey) left++; + std::swap(nums[left], nums[right]); + } + + return left; +} + + +void quickSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int pivot = partition(nums, left, right); + quickSort(nums, left, pivot - 1); + quickSort(nums, pivot + 1, right); + } + +} + + + +int main() { + std::vector nums = {2,1,3,6,4,7,5,8,9}; + + quickSort(nums, 0, nums.size() - 1); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + + + +int main() { + // std::vector nums = {-1,-2,-3}; + + // transform(nums.begin(), nums.end(), nums.begin(), [](int i) -> int { + // return i < 0 ? -i : i; + // }); + + // for(const int &n : nums) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + // int a = 0x1234; + // char *p = (char*)&a; + + // printf("%x\n", *(p+2)); + + // std::cout << *p << std::endl; + + // int a = 0x44332211; + // int *p1 = &a; + // char *p2 = (char*)&a; + // p2++; + + // printf("%x\n", *p1); + // printf("%x\n", *p2); + + // int *a = (((int*)0) + 4); + + // printf("%d\n", a); + + // long num = 0x0095AFF9F703A8; + + // printf("%lu\n", num); + + unsigned char *hex = "0x0095AFF9F703A8"; + + unordered_map hash = {{'A',10}, {'B',11}, {'C',12}, {'D',13}, {'E',14}, {'F',15}}; + + long long res = 0; + + int n = strlen(hex); + + for(int i = n - 1; i >= 0; i--) + { + + } + + return 0; +} + + +//给出一个用16进制表示的字符串,将该字符串转化成十进制数字表示 + + + +//开链法实现哈希 + + +#define HASHSIZE 10 //哈希表元素个数 + +typedef struct Node { + char *key; + char *value; + Node *next; +} Node; + + +class HashTable +{ +private: + Node *node[HASHSIZE]; + +public: + HashTable() { + memset(node, NULL, sizeof(node)); + } + + + //散列函数,计算key值位于node数组中的位置 + int Hash() {} + + //查找key值 + Node* find(const char *key) + { + int index = hash(key); //由散列函数计算出在节点数组node中的下标 + + Node *pNode = node[index]; + while(pNode) + { + //strcmp相同返回0 + if(!strcmp(pNode->key, key)) return pNode; + + pNode = pNode->next; + } + + return NULL; //表示未查找到 + } + + //插入键值对 + bool insert(const char *key, char *value) + { + Node *pNode = find(key); + + //key值不能存在 + if(pNode == NULL) + { + int index = hash(key); + pNode = (Node*)malloc(sizeof(Node)); + + if(pNode == NULL) return false; //申请失败则返回false + + pNode->key = key; + pNode->value = value; + node[index] = pNode; + } + + //key值已经存在,则更新value值 + pNode->value = value; + + return true; + } + + //删除某个key + bool deleteKey(const char *key) + { + Node *pNode = find(key); + if(pNode == NULL) return false; //不存在该key值 + + //找到要删除节点的上一个节点prev,将prev指向要删除节点的下一个节点 + int index = hash[key]; + if(node[index] == pNode) { + free(pNode); //不存在哈希冲突,也就是该位置链表只有一个节点 + pNode = NULL; + } + else { //存在哈希冲突 + Node *prev = node[index]; + while(prev->next != pNode) { + prev = prev->next; + } + prev->next = pNode->next; + free(pNode); + pNode = NULL; + } + + pNode = NULL; + return true; + } + +}; + + + +struct Node { + int value; + Node *next; +}; + +int main() { + // Node *p1 = (Node*)malloc(sizeof(Node)); + // p1->val = 1; + // p1->next = nullptr; + + Node* node[1]; + // memset(node, NULL, sizeof(node)); + node[0] = NULL; + + if(!node[0]->next) { + std::cout << "null" << std::endl; + } + + return 0; +} + +int kthSmallest(std::vector> &matrix, int k) +{ + int m = matrix.size(), n = matrix[0].size(); + + int left = matrix[0][0], right = matrix[m-1][n-1]; + + while(left <= right) + { + int mid = left + ((right - left) >> 1); + + for(int i = 0; i < m; i++) { + count += upper_bound(matrix[i].begin(), matrix[i].end(), mid) - matrix[i].begin(); + } + + if(count < k) { + left = mid + 1; + } + else if(count >= k) { + right = mid - 1; + } + } + + return left; +} + + + +/* +class A { +public: + void fun() { + std::cout << "A" << std::endl; + } +}; + +class B : public A { + +}; + +class C : public A { + +}; + +class D : public B, public C { +public: + void funD() { + std::cout << "D" << std::endl; + } +}; +*/ + +// class Base +// { +// private: +// virtual void fun() { std::cout << "Base" << std::endl; } +// friend void test() { +// std::cout << "hello" << std::endl; +// // fun(); +// }; +// }; + +// class Derived : public Base +// { +// public: +// void fun() { std::cout << "Derived" << std::endl; } +// }; + +// void test(); + +// class Base +// { +// public: +// // Base() { std::cout << "hello" << std::endl; } +// // Base() = default; +// Base(int m) : val(m) {} + +// private: +// int val; +// }; + + +// class Derived : public Base +// { +// public: +// Derived(int m_val): Base(m_val) {} + +// }; + + +// void fun(void) { +// std::cout << "hello" << std::endl; +// } +/* +void *fun(void) { + std::cout << "1" << std::endl; +} + +int insertSort(std::vector &nums); +int shellSort(std::vector &nums); +void heapSort(std::vector &nums); +void heapAdjust(std::vector &nums, int start, int end); + +int main() { + // typedef void(*pFunc)(void); + // void(*pFunc)(void); + // pFunc = fun; + + // pFunc(); + + // D d; + // d.funD(); + // A *ptr = new D(); + // ptr->funD(); + + // Base *ptr = new Derived() + // Derived d; + // d.fun(); + + // Base *ptr = new Derived(); + // ptr->fun(); + + // test(); + // Base b; + // b(1); + // Derived(1); + // Base a(1), b; + + // std::vector nums = {-1, 9,4,2,1,0}; + + // heapSort(nums); + + // for(const int &n : nums) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + + return 0; + + // atexit(fun); +} + +int insertSort(std::vector &nums) +{ + int n = nums.size(); + + for(int i = 1; i < n; i++) { + if(nums[i] < nums[i-1]) { + int tmp = nums[i]; + int j = i-1; + for(; j >= 0 && nums[j] >= tmp; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } + +} + + +int shellSort(std::vector &nums) +{ + int n = nums.size(); + int gap = n; + + while(gap >= 1) + { + gap = gap/3 + 1; + + for(int i = gap; i < n; i++) { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j = i - gap; + for(; j >= 0 && nums[j] >= tmp; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + if(gap == 1) break; + } + +} + + +void heapSort(std::vector &nums) +{ + int n = nums.size() - 1; + + for(int i = n/2; i >= 1; i--) { + heapAdjust(nums, i, n); + } + + for(int i = n; i > 1; i--) { + std::swap(nums[1], nums[i]); + heapAdjust(nums, 1, i-1); + } + +} + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int i = 2*start; i <= end; i *= 2) + { + if(i < end && nums[i] < nums[i+1]) i++; + + if(tmp > nums[i]) break; + + nums[start] = nums[i]; + + start = i; + } + + nums[start] = tmp; +} + + + + + +// int* find(int *arrayHead, int arraysize, int value) +// { +// int i = 0; +// for(; i < arraysize; i++) { +// if(arrayHead[i] == value) break; +// } + +// return &arrayHead[i]; +// } + +// int* find(int *begin, int *end, int value) +// { +// while(begin != end && *begin != value) begin++; + +// return begin; +// } + +template +T* find(T* begin, T* end, const T &value) +{ + while(begin != end && *begin != value) begin++; + + return begin; +} + + + + +#define max 100 + +std::string to_string(int n) +{ + int m = n; + char s[max], ss[max]; + + int i = 0, j = 0; + + if(n < 0) { + m = -n; + ss[j++] = '-'; + } + + while(m > 0) { + s[i++] = m%10 + '0'; + m /= 10; + } + + i--; + while(i >= 0) { + ss[j++] = s[i--]; + } + + ss[j] = '\0'; + + return ss; +} + +int main() { + // const int arraysize = 7; + // int ia[arraysize] = {0,1,2,3,4,5,6}; + + // int *end = ia + arraysize; + + // int *ip = find(ia, end, 4); + + // if(ip == end) std::cout << "Not Found" << std::endl; + // else std::cout << "Found" << std::endl; + + // std::shared_ptr sp1 = std::make_shared(10); + // std::shared_ptr sp2 = sp1; + + // std::cout << sp2.use_count() << std::endl; + + // std::cout << to_string(-12) << std::endl; + + std::stringstream in; + + int n = 100; + + in << n; + + std::string s1 = in.str(); + + std::cout << sizeof(s1) << std::endl; + + + return 0; +} + +// res = res*10 + (flag)*s[i]-'0' +// if res < 0, res*10 < INT_MIN || n > 8 return INT_MIN +// if res > 0, res*10 > INT_MAX || n > 7 return INT_MIN + +int myAtoi(std::string s) +{ + int res = 0; + + int i = 0; + while(isspace(s[i])) i++; + + bool minus = false; + if(s[i] == '-') { + minus = true; + i++; + } + else if(s[i] == '+') { + i++; + } + + int flag = minus ? -1 : 1; + + for(; i < s.size(); i++) + { + if(!isdigit(s[i])) break; + + if(res < INT_MIN/10 || (res == INT_MIN/10 && s[i] > '8')) return INT_MIN; + else if(res > INT_MAX/10 || (res == INT_MAX/10 && s[i] > '7')) return INT_MAX; + + res = res*10 + flag*(s[i] - '0'); + } + + return res; +} + + + +int main() { + std::vector>> nums(10000); + + int a,b,c; + char s; + + getchar(); + while(getchar() == '[') { + scanf("%d%c%d%c%d%c%c", &a, &s, &b, &s, &c, &s, &s); + nums[a].push_back({b,c}); + std::cout << a << " " << b << " " << c << std::endl; + } + + + return 0; +} + + +template +class shared_ptr +{ +private: + T *ptr; + int *count; + +public: + shared_ptr(T *pointer = nullptr) + { + if(pointer == nullptr) { + count = new int(0); + } + else { + ptr = pointer; + count = new int(1); + } + } + + shared_ptr(const shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + count = smartPtr.count; + + (*count)++; + } + + shared_ptr& operator=(const shared_ptr &smartPtr) + { + if(ptr != smartPtr.ptr) + { + if(ptr != nullptr && --(*count) == 0) { + delete ptr; + delete count; + } + + ptr = smartPtr.ptr; + count = smartPtr.count; + (*count)++; + } + } + + T& operator*() { return *ptr; } + + T* operator->() { return ptr; } + + ~shared_ptr() + { + if(ptr == nullptr) { + delete count; + } + else if(--(*count) == 0) { + delete ptr; + delete count; + } + } +}; + +/* +template +class weak_ptr +{ +public: + friend class shared_ptr; //方便shard_ptr的赋值 + T *ptr; + int *count; + + weak_ptr() { + ptr = nullptr; + count = nullptr; + } + + weak_ptr(shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + } + +}; + +struct Node { + int val; + shared_ptr next; + + Node(int m_val) : val(m_val) {} + + ~Node() { + std::cout << "~Destructor" << std::endl; + } + +}; + + + + +class String +{ +private: + char *str; + int len; + +public: + String(const char* s) + { + len = strlen(s); + str = new char[len + 1]; + strcpy(str, s); + } + + String(const String &demo) + { + len = demo.len; + str = new char[len + 1]; + strcpy(str, demo.str); + std::cout << "拷贝构造" << std::endl; + } + + String operator=(const String &demo) + { + if(this == &demo) return *this; + + delete[] str; + + len = demo.len; + str = new char[len + 1]; + strcpy(str, demo.str); + + std::cout << "赋值" << std::endl; + return *this; + } + + ~String() + { + std::cout << "析构" << std::endl; + delete[] str; + } + + void print() { + std::cout << str << std::endl; + } + +}; + + + +int main() { + + String str1("abc"); + str1 = str1; + // String str2("123"); + // String str3("456"); + // String str4; + + // str1.print(); + // str2.print(); + // std::cout << "hello" << std::endl; + // str1 = str2 = str3; + // std::cout << "hello" << std::endl; + // str4.print(); + + // shared_ptr sm(new int(10)); + // std::cout << *sm << std::endl; + // shared_ptr sm2(sm); + // sm = sm2; + // std::cout << *sm << std::endl; + + // shared_ptr p1 = new Node(1); + // shared_ptr p2 = new Node(2); + // std::cout << p1->val << std::endl; + // std::cout << p1->use_count() << std::endl; + // std::shared_ptr p1(new Node(1)); + // std::shared_ptr p2(new Node(2)); + // std::cout << p1->val << std::endl; + // p1->next = nullptr; + // p2->next = p1; + // pNode1->next = pNode2; + // pNode2->next = pNode1; + + // std::shared_ptr sp1 = std::make_shared(22); + // std::shared_ptr sp2 = sp1; + + // std::cout << *sp1 << " " << *sp2 << std::endl; + + // sp1.reset(); + + // std::cout << *sp1 << std::endl; + + return 0; +} + +class MyString +{ +private: + int *pData; + +public: + MyString(char *data = nullptr); + MyString(const MyString &demo); + ~MyString(); + + MyString& operator=(const MyString &demo); + +} + +MyString& MyString::operator=(const MyString &demo) +{ + if(this == &demo) return *this; + + delete[] pData; + + pData = new char[strlen(demo.pData) + 1]; //不是异常安全的 + memcpy(pData, str.pData); + + return *this; +} + +MyString& MyString::operator=(const MyString &demo) +{ + if(this != &demo) + { + MyString tmp(demo); + char *ptmp = tmp.pData; + tmp.pData = pData; + pData = ptmp; + } + + return *this; +} + + + + +void* memcpy(void *des, const void *src, size_t size) +{ + char *pDes = NULL, *pSrc = NULL; + + //泛型指针不能执行加减操作,但是可以比较大小 + //如果存在内存重叠则从后往前进行赋值 + if(src < des && (char*)src + size > (char*)des) + { + pDes = (char*)des + size - 1; + pSrc = (char*)src + size - 1; + while(size--) { + *pDes-- = *pSrc--; + } + } + else + { + //不存在内存重叠就从前往后赋值 + pDes = (char*)des; + pSrc = (char*)src; + while(size--) { + *pDes++ = *pSrc++; + } + } + + return des; +} + +char* strcpy(char *des, char *src) +{ + char *pDes = des; + + while((*des++ = *src++) != '\0'); + + return pDes; +} + +int strcmp(const char *str1, const char *str2); + + + +int main() { + char str1[] = "1", str2[] = "255"; + + std::cout << strcmp(str1, str2) < 0) return 1; + else if(res < 0) return -1; + + return res; +} + + + + + +std::mutex mtx; +std::condition_variable cv; +int ready = 0; + +void printString_1() +{ + std::unique_lock lk(mtx); + + int count = 0; + while(count < 10) + { + while(ready != 0) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "A" << std::endl; + + ready = 1; + count++; + cv.notify_all(); + } + +} + +void printString_2() +{ + std::unique_lock lk(mtx); + + int count = 0; + while(count < 10) + { + while(ready != 1) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "B" << std::endl; + + ready = 2; + count++; + cv.notify_all(); + } + +} + + +void printString_3() +{ + std::unique_lock lk(mtx); + + int count = 0; + while(count < 10) + { + while(ready != 2) cv.wait(lk); + + std::cout << std::this_thread::get_id() << " " << "C" << std::endl; + + ready = 0; + count++; + cv.notify_all(); + } + +} + + + + +int main() { + std::thread t1(printString_1); + std::thread t2(printString_2); + std::thread t3(printString_3); + + t1.join(); + t2.join(); + t3.join(); + + return 0; +} + + +int val = 0; +std::mutex mut; + +void increment1() +{ + for(int i = 0; i < 100; i++) { + // mut.lock(); + // val++; + // mut.unlock(); + } +} + +void increment2() +{ + for(int i = 0; i < 100; i++) { + // mut.lock(); + // val++; + // mut.unlock(); + } +} + +int main() { + std::thread t1(increment1); + std::thread t2(increment2); + + t1.join(); + t2.join(); + + std::cout << val << std::endl; + + return 0; +} + + +*/ + +/* + 十个人排队使用打印机,任一时刻只能有一个人使用,用一个变量0和1两种状态分别表示这台打印机能不能使用 +*/ +/* + +#include +#include +#include +#include + +std::vector tv; //保存线程的状态 +std::condition_variable cv; +std::mutex mut; + +int i = 1; //打印机资源,初始化为1,表示可用 + +/* +std::condition_variable_any cv; //下面使用自动锁,则这里需要使用_any +void subi() +{ + std::lock_guard locker(mut); //使用自动锁,调用即加锁,离开作用域即解锁 + + while(i == 0) { + cv.wait(mut); //资源不可用则阻塞等待 + } + + i--; //可以使用打印机 +} + +void addi() +{ + std::lock_guard locker(mut); + + i++; //将资源变为可用 + cv.notify_all(); //通知其他阻塞的线程可以使用了 +} +*/ +/* + +void subi() +{ + std::unique_lock lock(mut); + + while(i == 0) { + cv.wait(lock); + } + + i--; + + cv.notify_all(); +} + +void addi() +{ + std::unique_lock lock(mut); + + i++; //对共享资源的访问一定要加锁 + + cv.notify_all(); +} + + + +void func(int j) +{ + subi(); //模拟使用打印机 + std::cout << "I am thread " << j << ", i = " << i << std::endl; + addi(); //使用完归还打印机资源 +} + + +int main() { + for(int j = 0; j < 10; j++) { + std::thread t(func, j); + tv.push_back(std::move(t)); + } + + for(auto &thread : tv) { + thread.join(); + } + + return 0; +} + + +#include +#include +#include + +int k = 0; + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +void *fun1(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k != 0) { + pthread_cond_wait(&cond, &mutex); + } + + printf("A\n"); + + k = 1; + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + +void *fun2(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k != 1) { + pthread_cond_wait(&cond, &mutex); + } + + printf("B\n"); + + k = 2; + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + +void *fun3(void *arg) +{ + for(int i = 0; i < 10; i++) + { + pthread_mutex_lock(&mutex); + + while(k != 2) { + pthread_cond_wait(&cond, &mutex); + } + + printf("C\n"); + + k = 0; + + pthread_mutex_unlock(&mutex); + pthread_cond_broadcast(&cond); + } + +} + +int main() { + pthread_t tid1, tid2, tid3; + + pthread_create(&tid1, NULL, fun1, NULL); + pthread_create(&tid2, NULL, fun2, NULL); + pthread_create(&tid3, NULL, fun3, NULL); + + + pthread_join(tid1, NULL); + pthread_join(tid2, NULL); + pthread_join(tid3, NULL); + + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); + + return 0; +} +int firstNotSuccesiveNum(std::vector &nums) +{ + std::set mySet(nums.begin(), nums.end()); + + int x = *mySet.begin(); + + while(mySet.count(x)) { + x++; + } + + auto res = mySet.lower_bound(x); + if(res == mySet.end()) return -1; + + return *res; +} + + +std::vector theFreqencyOfNums(std::vector &nums) +{ + std::vector res(nums.size()); + + for(const int &n : nums) { + res[n-1]++; + } + + return res; +} +demo + + +int firstNotSuccesiveNum(std::vector &nums); +std::vector theFreqencyOfNums(std::vector &nums); + +int main() { + std::vector nums = {1,1,4,5,2,6}; + + // std::cout << firstNotSuccesiveNum(nums) << std::endl; + std::vector res = theFreqencyOfNums(nums); + + for(const int &n : res) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} +void dfs(int num, std::vector> &graph, std::vector °ree, std::vector &ans) +{ + if(ans.size() == num) { + res.push_back(ans); + return; + } + + for(int i = 1; i <= num; i++) + { + if(degree[i] == 0 && find(ans.begin(), ans.end(), i) == ans.end()) //ans中不存在这个数 + { + ans.push_back(i); + for(int &n : graph[ans.back()]) { + --degree[n]; + } + + dfs(num, graph, degree, ans); + + ans.pop_back(); + for(int &n : graph[ans.back()]) { + ++degree[n]; + } + } + } + +} + + +/* + 输出有向无环图的所有拓扑排序序列 + + +void dfs(int num, std::vector> &graph, std::vector indegree, std::vector &visited); + +std::vector ans; +std::vector> res; + + +//prepre表示节点的关系,num表示图的节点个数 +std::vector> topologySort(int num, std::vector> &prere) +{ + std::vector> graph(num + 1); //建立临接表(临接表与临接矩阵的区别在于临接表只存储与给定节点相邻的元素) + std::vector indegree(num + 1); //记录节点的入度(节点是从1开始编号的) + + for(auto &e : prere) { + graph[e[0]].push_back(e[1]); + indegree[e[1]]++; + } + + std::vector visited(num + 1, 0); + + dfs(num, graph, indegree, visited); + + return res; +} + + +void dfs(int num, std::vector> &graph, std::vector indegree, std::vector &visited) +{ + if(ans.size() == num) { + res.push_back(ans); + return ; + } + + for(int i = 1; i <= num; i++) + { + //该节点未遍历过,且度为0,则加入到结果中 + if(!visited[i] && indegree[i] == 0) + { + ans.push_back(i); + visited[i] = 1; + + for(const int &n : graph[i]) { + indegree[n]--; + } + + dfs(num, graph, indegree, visited); + + //回溯 + ans.pop_back(); + visited[i] = 0; + + for(const int &n : graph[i]) { + indegree[n]++; + } + } + } + +} + + +int main() { + + Singleton &demo = Singleton::getInstance(); + + // std::vector> prepre = {{1,2},{1,3},{2,4},{2,5},{3,4},{3,5},{4,6},{5,6}}; + // int num = 6; + + // /* + // std::vector ans = topologySort(num, prepre); + + // for(const int &n : ans) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + // */ + + // auto res = topologySort(num, prepre); + + // for(auto &num : res) { + // for(auto &n : num) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + // } +/* + return 0; +} + +/* +class Singleton +{ +private: + Singleton() { + std::cout << "我是懒汉式" << std::endl; + } //防止外部调用构造函数创建对象 + Singleton(Singleton const &single); //阻止拷贝创建对象 (将这两个函数放在public底下使用 =delete关键字来定义成删除函数也可以) + Singleton& operator=(Singleton const &single); //阻止复制运算符对对象复制 + +public: + + //懒汉式:只有调用getInstance函数才会创建对象 + static Singleton& getInstance() { //提供一个全局访问点,就需要在类中定义一个static函数,返回在类中的唯一构造的实例 + static Singleton instance; //这里的getInstace函数不能以值返回,主要是因为构造函数是私有的,外部不能创建临时对象 + return instance; + } + +}; + + + +class Singleton +{ +private: + Singleton() { + std::cout << "我是懒汉式" << std::endl; + } + Singleton(Singleton const &); + Singleton& operator=(Singleton const &); + static Singleton *instance; + static std::mutex mut; + +public: + static Singleton* getInstance() { + + //使用双检锁,只有判断指针为空的时候才加锁 + if(instance == nullptr) + { + std::unique_lock lock(mut); + if(instance == nullptr) { //注意这里也要判断一次,否则当两个线程同时进入时,刚开始instance都为空,第一个线程加完锁创建对象,第二个线程也会创建对象 + instance = new(std::nothrow) Singleton(); + } + } + return instance; + } + +}; + +Singleton* Singleton::instance = nullptr; +std::mutex Singleton::mut; //这个互斥锁必须初始化 + + + +void func() +{ + for(int i = 0; i < 3; i++) { + // std::cout << "thread1" << std::endl; + // Singleton *demo1 = Singleton::getInstance(); + Singleton &demo = Singleton::getInstance(); + // std::cout << demo1 << std::endl; + } +} + + + +int count = 0; + +void dfs(std::vector &nums, std::vector &visited, int steps) +{ + if(steps == 10) { + if(nums[1]*100 + nums[2]*10 + nums[3] + nums[4]*100 + nums[5]*10 + nums[6] == nums[7]*100 + nums[8]*10 + nums[9]) { + printf("%d%d%d + %d%d%d = %d%d%d\n", nums[1], nums[2], nums[3], nums[4], nums[5], nums[6], nums[7], nums[8], nums[9]); + count++; + } + return ; + } + + for(int i = 1; i <= 9; i++) + { + if(!visited[i]) + { + nums[steps] = i; + visited[i] = 1; + + dfs(nums, visited, steps + 1); + + visited[i] = 0; + } + } + +} + +std::string addTwoNumber(std::string num1, std::string num2); + +int main() { + // std::vector nums(10), visited(10, 0); + + // dfs(nums, visited, 1); + + // std::cout << count/2 << std::endl; + + std::string num1 = "1", num2 = "999"; + + std::cout << addTwoNumber(num1, num2) << std::endl; + + return 0; +} + +std::string addTwoNumber(std::string num1, std::string num2) +{ + if(num1.empty()) return num2; + else if(num2.empty()) return num1; + + reverse(num1.begin(), num1.end()); + reverse(num2.begin(), num2.end()); + + std::string res; + int carry = 0; + int i = 0, j = 0; + + while(i < num1.size() || j < num2.size() || carry) + { + carry += (i < num1.size() ? (num1[i++]-'0') : 0) + (j < num2.size() ? (num2[j++] - '0') : 0); + + res += std::to_string(carry%10); + + carry /= 10; + } + + reverse(res.begin(), res.end()); + + return res; +} + + +int i = 0; + +void selfIncreasing() { + for(int j = 0; j < 1000000; j++) { + i++; + } +} + +int fun1(int i); +int fun2(unsigned int n); + +int f(int m, int n) ; + + +int main() { + + std::cout << f(30, 10) << std::endl; + + // std::cout << fun2(fun1(101)) << std::endl; + + // std::thread threadOne(selfIncreasing); + // std::thread threadTwo(selfIncreasing); + + // threadOne.join(); + // threadTwo.join(); + + // std::cout << i << std::endl; + + // auto add = [](int a, int b) -> int { return a + b; }; + + // std::cout << add(1,2) << std::endl; + + // std::cout << add(1,2) << std::endl; + // std::cout << "hello" << std::endl; + + + // int a = 1, b = 1, c = 1, d = 1, e + + return 0; +} + + + +int f(int m, int n) +{ + if(n == 0) return 1; + else if(m < n) return 0; + + return f(m-1, n) + f(m, n-1); +} + +int fun1(int i) +{ + return i < 10 ? i : (5*fun1(i-1) + 2*fun1(i-2) + fun1(i-3) + fun1(i-4)) & 0x5ffff; +} + +int fun2(unsigned int n) +{ + unsigned int f = 2020; + return (f&n)/2; +} + +void bubbleSort(std::vector &nums) +{ + int n = nums.size(); + + bool flag = true; + + for(int i = 0; i < n && flag; i++) + { + flag = false; + + for(int j = n-2; j >= i; j--) + { + if(nums[j] > nums[j+1]) { + std::swap(nums[j], nums[j+1]); + flag = true; + } + } + } + +} + +void selectSort(std::vector &nums) +{ + int n = nums.size(); + + for(int i = 0; i < n; i++) + { + int min = i; + for(int j = i + 1; j < n; j++) { + if(nums[min] > nums[j]) min = j; + } + + if(min != i) std::swap(nums[i], nums[min]); + } + +} + +void insertSort(std::vector &nums) +{ + int n = nums.size(); + + for(int i = 1; i < n; i++) + { + if(nums[i] < nums[i-1]) + { + int tmp = nums[i]; + int j = i - 1; + for(; j >= 0 && nums[j] > tmp; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } +} + +void shellSort(std::vector &nums) +{ + int gap = nums.size(), n = nums.size(); + + while(gap >= 1) + { + gap = gap/3 + 1; + + for(int i = gap; i < n; i++) + { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j = i - gap; + for(; j >= 0 && nums[j] > tmp; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + + if(gap == 1) break; + } + +} + +std::pair find() { + return {}; +} + + +//方法一: +#define MIN(a, b) ((a) < (b) ? (a) : (b)) //加括号防止预处理展开的错误 + +// #define MIN(a, b) ({\ +// if(a < b) return a; \ +// return b;\ +// }) + +//方法二:(宏里面如果有多行代码则需要使用 {} ) +// #define MIN(a, b) ({ \ +// typeof(a) m_x = (a); \ +// typeof(b) m_y = (b); \ +// (m_x < m_y) ? m_x : m_y; \ +// }) + +//1.typeof关键字用来获得变量的数据类型, +//2.宏定义的实现,用{}作为宏整体,里面是一个代码块,语句用";"隔开 +//3.当宏的实现很长的时候,使用换行符 "\" 换到下一行 +//4.使用输入数据的类型定义局部变量 m_x, m_y 实现对原始数据的保护 +//5.宏实现不能使用 ";" 结尾 + +int min(int x, int y, int z) +{ + return x < y ? (x < z ? x : z) : (y > z ? z : y); +} +int findLucky(std::vector &arr) +{ + std::vector arr(501,0); + + for(const int &n : arr) { + arr[n]++; + } + + for(int i = 500; i > 0; i--) { + if(arr[i] == i) return i; + } + + return -1; +} + +int findLucky(std::vector &arr) +{ + sort(arr.rbegin(), arr.rend()); + + int count = 1; + for(int i = 0; i < arr.size() - 1; i++) { + if(arr[i] == arr[i+1]) { + count++; + } + else { + if(count == arr[i]) return arr[i]; + count = 1; + } + } + + return arr.back() == count ? count : -1; +} + +std::vector luckyNumbers(std::vector> &matrix) +{ + std::vector res; + + int m = matrix.size(), n = matrix[0].size(); + if(m == 0 || n == 0) return res; + + std::vector rowMin(m, INT_MAX), colMax(n, INT_MIN); + + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { + rowMin[i] = std::min(matrix[i][j], rowMin[i]); + colMax[j] = std::max(matrix[i][j], colMax[j]); + } + } + + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { + if(rowMin[i] == colMax[j]) res.push_back(rowMin[i]); + } + } + + return res; +} + + +int main() { + std::cout << MIN(1,2) << std::endl; + // std::cout << MIN(1,2) << std::endl; + // std::cout << min(10,2,3) << std::endl; + + return 0; +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct ListNode { + int val; + ListNode *next; + + ListNode(int x) : val(x), next(nullptr) {} + ~ListNode() { + std::cout << "析构" << std::endl; + delete next; + } +}; + + +void fun() +{ + std::cout << std::this_thread::get_id() << std::endl; +} + + +int main() { + // ListNode *pNode = new ListNode(1); + // delete pNode; + + // std::pair anon = {}; + + // if(anon.second.empty()) { + // std::cout << "fail" << std::endl; + // } + + // std::set iset = {0,1,2,3,4,5}; + // std::set::iterator set_it = iset.cbegin(); + + // std::cout << *set_it << std::endl; + + // for(int i = 0; i < 10; i++) { + std::thread t1(fun); + // } + + t1.join(); + + return 0; +} + +void print_even(int x) +{ + if(x%2 == 0) { + std::cout << x << " is even" << std::endl; + } + else { + throw(std::logic_error("not even")); + } +} + +void print_id(int id) +{ + try { + std::lock_guard lock(mut); + print_even(id); + } + catch (std::logic_error &) { + std::cout << "except\n" << std::endl; + } +} + +int main() { + std::thread threads[10]; + // std::vector threads(10); + for(int i = 0; i < 10; i++) { + threads[i] = std::thread(print_id, i + 1); + } + + for(auto &th : threads) { + th.join(); + } + + return 0; +} + + +std::mutex mut; +std::condition_variable cv; + +int k = 0; + +void print1() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 0) cv.wait(lock); + + printf("A\n"); + + k = 1; + + sleep(1); + + cv.notify_all(); + } +} + +void print2() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 1) cv.wait(lock); + + printf("B\n"); + + k = 2; + + sleep(1); + + cv.notify_all(); + } +} + +void print3() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 2) cv.wait(lock); + + printf("C\n"); + + k = 0; + + sleep(1); + + cv.notify_all(); + } +} + + +int main() { + std::thread t1(print1), t2(print2), t3(print3); + + t1.detach(); + t2.join(); + t3.join(); + + return 0; +} + +bool isPalindrome(ListNode *head) +{ + if(head->next == nullptr) return true; + + ListNode *fast = head, *slow = head; + + while(fast->next && fast->next->next) { + fast = fast->next->next; + slow = slow->next; + } + + ListNode *mid = slow->next; + slow->next = nullptr; + + ListNode *head2 = reverse(mid); + + while(head && head2) + { + if(head->val != hea2->val) return false; + + head = head->next; + head2 = head2->next; + } + + return true; +} + + +ListNode *reverse(ListNode *head) +{ + ListNode *prev = nullptr; + + while(head) { + ListNode *pNext = head->next; + head->next = prev; + prev = head; + head = pNext; + } + + return prev; +} + + +#include +#include +#include +#include +#include +#include + +const int size = 1000; + +int data[size]; + +int head = 0; +int tail = 0; + +void push(int n) +{ + if((tail + 1)%size == head) return; + data[tail] = 0; + tail = (tail+1)%size; +} + +void pop() +{ + if(head == tail) return; + + head = (head + 1)%size; +} + + + +int main() { + + + return +} + +std::vector nums; +int size; +int head, tail; + +MyCircularQueue(int k) { + size = k + 1; + nuns.resize(size); + head = tail = 0; +} + +bool isEmpty() +{ + if(head == tail) return true; + return false; +} + +bool isFull() +{ + if((tail+1)%size == head) return true; + return false; +} + +bool enQueue(int value) +{ + if(ifFull) return false; + nums[tail] = value; + tail = (tail + 1)%size; + return true; +} + +bool deQueue() +{ + if(isEmpty()) return false; + head = (head + 1)%size; + return true; +} + +int front() { + return nums[head]; +} + +int Rear() { + int tmp = tail; + return nums[--tmp]; +} + + +int GetSteps(int k); + +int main() { + std::cout << GetSteps(5) << std::endl; + + return 0; +} + +int GetSteps(int k) +{ + if(k <= 1) return 0; + + if(k&1) return 0; //因为一来一回需要两次,所以k为奇数则不能到达原点 + + int n = 10; //10个点 + + std::vector> dp(k+1, std::vector(n, 0)); + dp[0][0] = 1; + + for(int i = 1; i <= k; i++) { + for(int j = 0; j < n; j++) { + dp[i][j] = dp[i-1][(j-1+n)%n] + dp[i-1][(j+1)%n]; + } + } + + return dp[k][0]; +} + + +int heapAdjust(std::vector &nums, int start, int end); + +void heapSort(std::vector &nums) +{ + int n = nums.size() - 1; + + for(int i = n/2; i >= 1; i--) { + heapAdjust(nums, i, n); + } + + for(int i = n; i > 1; i--) { + std::swap(nums[1], nums[i]); + heapAdjust(nums, 1, i-1); + } + +} + +int heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j *= 2) + { + if(j < end && nums[j] < nums[j+1]) j++; + + if(tmp > nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; +} + + +// #define swap(x, y) ({typeof(x) tmp = x; x = y; y = tmp;}) +// #define swap(x, y) ({ typeof(x) tmp = x; x = y; y = tmp; }) + + + +std::vector> path; + +int minimumTota(std::vector> triangle) +{ + int m = triangle.size(), n = triangle[0].size(); + + path = std::vector>(m, std::vector(n)); + + // std::vector tmp = triangle[m-1]; + + for(int i = m-2; i >= 0 ; i--) { + for(int j = 0; j <= i; j++) { + triangle[i][j] += std::max(triangle[i+1][j], triangle[i+1][j+1]); + // tmp[j] = std::min(tmp[j], tmp[j+1]) + triangle[i][j]; + + if(triangle[i+1][j] > triangle[i+1][j+1]) { + path[i][j] = 1; + } + else { + path[i][j] = 2; + } + + } + } + + return triangle[0][0]; +} + +void print(std::vector> triangle, int i, int j) +{ + if(i >= triangle.size()) return ; + + std::cout << triangle[i][j] << std::endl; + + if(path[i][j] == 1) { + print(triangle, i+1, j); + } + else if(path[i][j] == 2) { + print(triangle, i+1, j+1); + } + +} + +void deleteEven(std::vector &nums) +{ + for(auto it = nums.begin(); it != nums.end();) + { + if((*it)&1) { //如果是奇数 + it++; + } + else { + it = nums.erase(it); + } + } +} + + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + while(gap >= 1) + { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) + { + if(nums[i] < nums[i-gap]) + { + int tmp = nums[i]; + int j = i - gap; + for(; nums[j] > tmp && j >= 0; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + break; + if(gap == 1) break; //避免死循环,当跨度等于1直接跳出 + } + +} + + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + + static Singleton* instance; + +public: + static Singleton* getInstance() { + return instance; + } + + void deleteInstance() { + if(instance) delete instance; //释放单实例 + instance = nullptr; + } + +}; + +Singleton* Singleton::instance = new(std::nothrow) Singleton; + + +int main() { + + // std::list mylist = {1,-1,-1,0,-1,2}; + + // for(auto it = mylist.begin(); it != mylist.end();) + // { + // if(*it == -1) { + // it = mylist.erase(it); + // } else{ + // it++; + // } + // } + + // for(auto &n : mylist) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + // Singleton* demo = Singleton::getInstance(); + + // printf("%d\n", demo); + + // std::vector nums = {9,1,5,8,3,7,4,6,2}; + + // shellSort(nums); + + // // heapSort(nums); + + // for(const int &n : nums) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + // int a = 1, b = 2; + // swap(a,b); + + // std::cout << a << " " << b << std::endl; + + // std::vector> triangle = {{7}, {3,8}, {8,1,0}, {2,7,4,4}, {4,5,2,6,5}}; + + // std::cout << minimumTota(triangle) << std::endl; + + // print(triangle, 0, 0); + + // std::vector nums = {0,1,2,3,4,3}; + + // // deleteEven(nums); + // nums.erase(nums.begin(), nums.begin() + 1); + + // for(const int &n : nums) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + std::vector nums = {1,2,3}; + + nums.resize(nums.size(), 0); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + +class BitMap +{ +private: + std::vector vec; + +public: + BitMap(size_t size) { //size_t为无符号整形,不会存在负数.size为存储的元素总个数 + vec.resize(size/32 + 1); //每个整形可以存储32个数,当size<32时,size/32=0,因此为了保证小于32的元素个数能存储,需要加1 + } + + //设置第x bit位为1 + bool set(size_t x) + { + if(x/32 > vec.size()) { + return false; + } + + size_t index = x/32; //找到是第几个数 + size_t num = x%32; //找到是在vec[index]第几个bit位 + + vec[index] |= (1 << num); + return true; + } + + bool reset(size_t x) //将x的状态为置为0 + { + if(x/32 > vec.size()) { + return false; + } + + size_t index = x/32; + size_t num = x%32; + + vec[index] ^= (1 << num); + return true; + } + + int find(size_t x) //查找x的状态并返回 + { + if(x/32 > vec.size()) { + return -1; + } + + size_t index = x/32; + size_t num = x%32; + + return (vec[index] >> num) & 1; + } + + + void clear() //置空该位图 + { + vec.clear(); + } + +}; + + +// class A +// { +// public: +// int test() { +// std::cout << "A" << std::endl; +// } +// }; + +// class B : public A { +// public: +// int test() { +// std::cout << "B" << std::endl; +// } +// }; + +class A { +public: + A() { printf("A\n"); } + virtual ~A() { printf("~A\n"); } +}; + +class B : public A { +public: + B() { printf("B\n"); } + ~B() { printf("~B\n"); } +}; + +class Base { +private: + virtual void fun() { std::cout << "Base" << std::endl; } + // friend int main(); +}; + +class Derived : public Base { +public: + void fun() { std::cout << "Derived" << std::endl; } +}; + + + +int main() { + Base *ptr = new Base(); + ptr->fun(); + + // A *c = new B(); + // delete c; + + // A *p = new B(); + // p->test(); + + // BitMap map(30); + + // map.set(1); + // map.set(10); + // map.set(20); + + // map.reset(20); + + // std::cout << map.find(20) << std::endl; + + return 0; +} + +class MyVector +{ +private: + int *data; + int capacity; + int size; + + void addsize(int newsize) + { + int newData = new int[newsize]; + for(int i = 0; i < size; i++) { + newData[i] = data[i]; + } + delete[] data; + + data = newData; + capacity = newsize; + } + +public: + MyVector() : data(nullptr), capacity(0), size(0) {} + + ~MyVector() { + delete[] data; + } + + MyVector(int m_size, int val) { + data = new int[m_size]; + memset(data, val, sizeof(data)); + capacity = m_size; + size = m_size; + } + + void push_back(int val) + { + if(capacity == size) { + addsize(size*2); + } + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + int& operator[](int i) { + return data[i]; + } + +}; + + +class MyVector +{ +private: + int *data; + int size; + int capacity; + + void addsize(int newsize) + { + int *newData = new int[newsize]; + for(int i = 0; i < size; i++) { + newData[i] = data[i]; + } + delete[] data; + + data = newData; + capacity = newsize; + } + +public: + MyVector(): data(nullptr), capacity(0), size(0) {} + + ~MyVector() { + delete[] data; + } + + MyVector(int m_size, int val) { + data = new int[m_size]; + memset(data, val, sizeof(data)); + capacity = m_size; + size = m_size; + } + + void push_back(int val) + { + if(capacity == size) { + addsize(size*2); + } + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + int& operator[](int i) { + return data[i]; + } + +}; + + +template +class shared_ptr +{ +private: + T *ptr; + int *count; + +public: + shared_ptr(T *pointer = nullptr) + { + ptr = pointer; + + if(ptr == nullptr) { + count = new int(0); + } + else { + count = new int(1); + } + } + + shared_ptr(const shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + count = smartPtr.count; + + (*count)++; + } + + shared_ptr& operator=(const shared_ptr &smartPtr) + { + if(ptr != smartPtr.ptr) + { + if(ptr != nullptr && --(*count) == 0) { + delete ptr; + delete count; + } + + ptr = smartPtr.ptr; + count = smartPtr.count; + + (*count)++; + } + + return *this; + } + + T& operator*() { return *ptr }; + + T& operator->() { return ptr; } + + ~shared_ptr() + { + if(ptr == nullptr) delete count; + else if(--(*count) == 0) { + delete ptr; + delete count; + } + } + + int use_count() { return *count; } +}; + + +template +class weak_ptr +{ +public: + friend class shared_ptr; + + T *ptr; + int *count; + + weak_ptr() { + ptr = nullptr; + count = nullptr; + } + + weak_ptr(const shared_ptr smartPtr) { + ptr = smartPtr.ptr; + } + +}; + + +void insertSort(std::vector &nums); + +struct Node { + int data; + std::weak_ptr next; + + Node(int n) : data(n) {} + + ~Node() { + std::cout << "~Node()" << std::endl; + } +}; + +int main() { + // std::shared_ptr p1(new Node(1)); + // std::shared_ptr p2(new Node(2)); + + // p1->next = p2; + // p2->next = p1; + + std::vector nums = {0,4,3,2,1}; + + insertSort(nums); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) + { + if(nums[i] < nums[i-1]) { + int tmp = nums[i]; + int j = i-1; + for(; j >=0 && nums[j] > tmp; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } + +} + + + +class String +{ +private: + char *str; + +public: + String(const char *s = NULL) + { + if(s == NULL) { + str = new char[1]; + *str = '\0'; + } + else { + str = new char[strlen(s) + 1]; + strcpy(str, s); + } + } + + String(const String &demo) + { + str = new char[strlen(demo.str) + 1]; + strcpy(str, demo.str); + } + + String& operator=(const String &demo) + { + if(this == &demo) return *this; + + delete[] str; + + str = new char[strlen(demo.str) + 1]; + strcpy(str, demo.str); + + return *this; + } + + String operator+(const String &demo) const + { + char *sp = new char[strlen(demo.str) + strlen(str) + 1]; + strcpy(sp, str); + strcat(sp, demo.str); + + String tmp(sp); + return tmp; + } + + ~String() { + delete[] str; + } + + void print() { + std::cout << str << std::endl; + } + +}; + + +void func_int(void *a) +{ + printf("%d\n", *(int*)a); +} + + +void func_double(void *b) +{ + printf("%f\n", *(double*)b); +} + +typedef void (*ptr)(void*); + +void c_func(ptr p, void *arg) +{ + p(arg); +} + + +typedef void(*func)(); //定义一个函数指针来实现对成员函数的继承 + +//父类 +struct A { + func fun; //由于C语言结构体中不能包含函数,故只能用函数指针在类外实现 +}; + +//子类 +struct B { + A m_a; //子类中定义一个基类的对象来实现对父类的继承 +}; + +void fA() { //父类的调用函数 + printf("A::\n"); +} + +void fB() { //子类的调用函数 + printf("B::\n"); +} + + + +int main() +{ + A a; + B b; + + a.fun = fA; //父类的对象调用父类的函数 + b.m_a.fun = fB; //子类的对象调用子类的函数 + + A* p2 = &a; //定义父类指针指向父类的对象 + p2->fun(); + + p2 = (A*)&b; //让父类指针指向父类的对象,由于类型不匹配需要强制转换 + p2->fun(); +} + + // int a = 23; + // double b = 23.23; + + // c_func(func_int, &a); + // c_func(func_double, &b); + + // String str1("hello"), str2("world"); + + // String str3 = str1 + str2; + + // str3.print(); + + // char str1[] = "hello", str2[] = "world"; + + // std::cout << str3 << std::endl; + + return 0; +} + +std::string multiplyTwoNumber(std::string num1, std::string num2) +{ + int m = num1.size(), n = num2.size(); + + std::string res(m + n, '0'); + + for(int i = m-1; i >= 0; i--) { + for(int j = n-1; j >= 0; j--) { + int prod = (num1[i]-'0')*(num2[j]-'0') + res[i+j+1]; + res[i+j+1] = prod%10 + '0'; + res[i+j] += prod/10; + } + } + + for(int i = 0; i < res.size(); i++) { + if(res[i] != '0') return res.substr(i); + } + + return "0"; +} + + +* + +class A { +public: + A() { + std::cout << "A" << std::endl; + } + void print() { + std::cout << "hello" << std::endl; + } +}; + +class C { +public: + C() { + std::cout << "C" << std::endl; + } +}; + +class B : public A { + C c; +public: + B() : c(){ + std::cout << "B" << std::endl; + } +}; + + + + +// class B : virtual public A {}; +// class C : virtual public A {}; + +// class D : public B, public C {}; + + +int main() { + + B b; + + // D d; + // d.print(); + // d.B::print(); + // d.C::print(); + + return 0; +} + +std::mutex mut; +std::condition_variable cv; + +int k = 0; //区分线程 + +std::string s1 = "abcd"; +std::string s2 = "1234"; + +void print1() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s1.size(); i++) + { + while(k != 0) cv.wait(lock); + std::cout << s1[i] << std::endl; + k = 1; + + sleep(1); //打印完暂停一秒看出变化 + + cv.notify_all(); + } + } + +} + +void print2() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s2.size(); i++) + { + while(k != 1) cv.wait(lock); + std::cout << s2[i] << std::endl; + k = 0; + sleep(1); + cv.notify_all(); + } + } + +} + + +int rand4() +{ + return rand()%5; +} + +int rand6() +{ + int n = rand4()*5 + rand4(); + + while(n > 20) { + n = rand4()*5 + rand4(); + } + + return n%7; +} + + +int rand5() { + srand(time(0)); + return rand()%5 + 1; +} + +int rand7() { + int n = (rand5()-1)*5 + rand5(); + + while(n > 21) { + n = (rand5()-1)*5 + rand5(); + } + + return n%7 + 1; +} + + +void shuffle(std::vector &nums) +{ + for(int i = nums.size() - 1; i >= 0; i--) + { + int j = rand()%(i+1); + std::swap(nums[i], nums[j]); + } + +} + + +void merge(std::vector &nums, int left, int right, int mid); + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right - left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, right, mid); + } + +} + +void merge(std::vector &nums, int left, int right, int mid) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right-left+1]; + int index = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] < nums[rindex]) { + team[index++] = nums[lindex++]; + } + else { + team[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + team[index++] = nums[lindex++]; + } + + while(rindex <= right) { + team[index++] = nums[rindex++]; + } + + for(int i = 0; i < index; i++) { + nums[left+i] = team[i]; + } + + delete[] team; +} + +int main() { + + std::vector nums = {50,10,90,30}; + + mergeSort(nums, 0, nums.size() - 1); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + // std::cout << rand7() << std::endl; + // std::thread t1(print1), t2(print2); + // t1.join(); + // t2.join(); + + return 0; +} + + +int reversePairs(std::vector &nums) +{ + return mergeSort(nums, 0, nums.size() - 1); +} + +int mergeSort(std::vector &nums, int left, int right) +{ + if(left >= right) return 0; + + int mid = left + ((right - left) >> 1); + + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + + std::vector tmp(right - left + 1); + int index = 0; + + int lindex = left, rindex = mid + 1; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] <= nums[rindex]) { + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + else { + tmp[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + count += rindex - (mid + 1); + tmp[index++] = nums[lindex++]; + } + + while(rindex <= right) { + tmp[index++] = nums[rindex++]; + } + + for(int i = 0; i < index; i++) { + nums[left+i] = tmp[i]; + } + + return count; +} + + + +void subtractOne(std::string &str); + +int main() { + std::string str; + std::cin >> str; + + if(str == "0") { + std::cout << "-1" << std::endl; + return 0; + } + else if(str == "1") { + std::cout << "0" << std::endl; + return 0; + } + + subtractOne(str); + + for(int i = 0; i < str.size(); i++) { + if(str[i] != '0') { + std::cout << str.substr(i) << std::endl; + break; + } + } + + return 0; +} + +void subtractOne(std::string &str) +{ + int n = str.size(); + if(str[n-1] == '0') { + int i = n-1; + while(str[i] == '0') i--; + str[i]--; + for(int j = i + 1; j < str.size(); j++) str[j] = '9'; + } + else { + str[n-1]--; + } + +} + + +bool bigger(const std::string &num1, const std::string &num2) +{ + if(num1.size() != num2.size()) return num1.size() > num2.size(); + + for(int i = 0; i < num1.size(); i++) { + if(num1[i] != num2[i]) return num1[i] > num2[i]; + } + + //这里返回true或者false都可以,这一句永远不会被执行 + return false; +} + +std::string subTwoNumber(std::string num1, std::string num2) +{ + if(num1 == num2) return "0"; + + //让num1始终比num2大,这样方便处理借位 + bool positive = bigger(num1, num2); + + if(!positive) { + std::swap(num1, num2); + } + + //将num2的长度补齐到和num1一样 + while(num1.size() > num2.size()) { + num2 = "0" + num2; + } + + for(int i = num1.size() -1; i >= 0; i--) + { + //不足就向上一位借位 + if(num1[i] < num2[i] && i > 0) { + num1[i-1]--; + num1[i] += 10; + } + + num1[i] -= (num2[i] - '0'); + } + + std::string res = num1; + + if(res[0] == '0') res = res.substr(1); //去掉开头的0,比如 "100" - "1" = "099" + + if(!positive) res = "-" + res; + + return res; +} + + +int main() { + std::string num1 = "100", num2 = "10"; + + std::cout << subTwoNumber(num1, num2) << std::endl; + + return 0; +} + + +//C语言实现函数重载 + +void func_int(void *a) +{ + printf("%d\n", *(int*)a); +} + +void func_double(void *a) +{ + printf("%f\n", *(double*)a); +} + +typedef void (*ptr)(void *); + +void c_func(ptr p, void *arg) +{ + p(arg); +} + + +/* +int main() { + int a = 23; + double b = 23.23; + + c_func(func_int, &a); + c_func(func_double, &b); + + return 0; +} + + +typedef void(*func)(); + +struct A { + func fun; +}; + +struct B { + struct A m_a; +}; + + +void fA() { + printf("A::\n"); +} + +void fB() { + printf("B::\n"); +} + + +// typedef void (*p)(); + +const char* getString(char *ptr) +{ + return ptr; +} + + + +// int main() { +// char str[] = "abc"; +// const char *ptr = getString(str); +// // std::cout << *ptr << std::endl; +// printf("%s\n", ptr); +// // void (*ptr)(); +// // ptr = fA; +// // (*ptr)(); + +// // p fun; +// // fun = fA; +// // fun(); + +// // A a; +// // B b; + +// // a.fun = fA; +// // b.m_a.fun = fB; + +// // A *p = &a; +// // p->fun(); + +// // p = (A*)&b; +// // p->fun(); + +// return 0; +// } + + +void* memcpy(void *des, const void *src, size_t size) +{ + char *pDes = NULL, *pSrc = NULL; + + if(src < des && (char*)src + size > (char*)des) + { + pDes = (char*)des + size - 1; + pSrc = (char*)src + size - 1; + while(size--) { + *pDes-- = *pSrc--; + } + } + else //不存在内存重叠 + { + pDes = (char*)des; + pSrc = (char*)src; + while(size--) { + *pDes++ = *pSrc++; + } + } + + return des; +} + + +void strcpy(char *des, char *src) +{ + if(des == nullptr || src == nullptr) return; + + char *pDes = des, *pSrc = src; + + while((*pDes++ = *pSrc++) != '\0'); + + // return des; +} + + +#include +#include +#include +#include +#include +#include +#include + +class A { +public: + int data; + A() : data(100) {} + void print() { std::cout << data << std::endl; } +}; + +class B : public A { +public: + int val; + B(): val(200) {} + void print() { std::cout << val << std::endl; } +}; + +void print(int (&arr)[5]) { + for(auto n : arr) + std::cout << n << " "; +} + +template +int compare(const T&, const T&) { + return 0; +} + + +int main() { + + + // long lng; + // // compare(lng,1024); + + // compare(lng, 1024); + + // compare("bye", "dats"); + + // int i = 10; + // int j[] = {1,2,3,4,5}; + + // print(&i); + + // std::map hash = {{1,1}, {2,2}, {3,3}, {4,4}, {5,5}}; + + // std::vector hash = {1,2,3,4,5}; + + // for(auto it = hash.begin(); it != hash.end();) + // { + // if(*it & 1) hash.erase(it++); + // else it++; + + + // for(std::pair &item : hash) { + // std::cout << item.first << " " << item.second << " "; + // } + // std::cout << std::endl; + + // remove_if(hash.begin(), hash.end(), [](auto item){return !(item.second&1);}); + + // hash.erase(remove_if(hash.begin(), hash.end(), [](std::pair &item){ return !(item.first&1); }), hash.end()); + + // A *p = new A(); + + // B *ptr = static_cast(p); + + // ptr->print(); + + // char str1[10]; + // const char str2[] = "abc"; + + // char *ptr = str2; + + // int n = 5; + // const int * ptr = &n; + // // const int *ptr = &n; + // int *p = ptr; + // ptr = new int(4); + + // strcpy(str1, str2); + + // printf("%s\n", str1); + + return 0; +} + + +// #include +// #include +// #include + +template +bool isPtr(T *p) +{ + return true; +} + +bool isPtr(...) +{ + return false; +} + +class Test { +public: + Test() {} + virtual ~Test(){} +}; + +int main() { + // Test *p = new Test(); + // // Test p; + + // int i = 0; + + Test t; + // Test *pt = &t; + + std::cout << isPtr(t) << std::endl; + + + return 0; +} + + +int strcmp(const char *str1, const char *str2) +{ + int res = 0; + + while(!(res = *(unsigned char*)str1 - *(unsigned char*)str2) && *str1++ && *str2++); + + if(res > 0) return 1; + else if(res < 0) return -1; + + return 0; +} + + +struct MyStruct { + int a; +}; + +class Test1 { + MyStruct struct1; +}; + +class Test2 { + MyStruct *str; +}; + + +void func(std::string &str, const std::string &from, const std::string &to) +{ + size_t pos = 0; + while((pos = str.find(from, pos)) != std::string::npos) { + str.replace(pos, from.size(), to); + pos += to.size(); + } +} + +const int max = 100; + +std::string to_string(int n) +{ + int m = n; + char s[max], ss[max]; + int i = 0, j = 0; + + if(n < 0) { + m = -n; + ss[j++] = '-'; + } + + while(m > 0) { + s[i++] = m%10 + '0'; + m /= 10; + } + + i--; + while(i >= 0) { + ss[j++] = s[i--]; + } + + ss[j] = '\0'; + + return ss; +} + + +template +int compare(const char(&)[N], const char(&)[M]) {} + +template +int compare(const T & a, const T &b) +{ + return a < b; +} + + +template +void foo(const T&, const Args& ... args) { + std::cout << sizeof ... (Args) << std::endl; + std::cout << sizeof ... (args) << std::endl; +} + + +int main() { + std::vector nums = {1,2,3}; + + if(auto it = find(nums.begin(), nums.end(), 3); it != nums.end())) *it = 4; + + + + + // int i = 0; + // double d = 3.14; + // std::string s = "how"; + + // foo(i, s, 42, d); + + // const char *p1 = "hi", *p2 = "mom"; + // std::cout << compare("hi", "mom") << std::endl; + + // std::vector nums = {1,2,3}; + // nums.resize(4); + + // for(const int &n : nums) { + // std::cout << n << " "; + // } + // std::cout << std::endl; + + // std::cout << to_string(-289) << std::endl; + + // std::string str = "helloworldllo"; + // std::string from = "llo", to = "abc"; + + // func(str, from, to); + + // std::cout << str << std::endl; + + // std::map, int >mp; + + // mp[{1,1}]++; + + // std::string str = "dsdhelloew", from = "hello", to = "world"; + + // func(str, from, to); + + // std::cout << str << std::endl; + + // std::cout << sizeof(Test1) << std::endl; + // std::cout << sizeof(Test2) << std::endl; + // char str1[] = "", str2[] = "a"; + + // std::cout << strcmp(str1, str2) << std::endl; + + return 0; +} + +int findMaxLength(std::string &str); +int findMaxGuests(std::vector &start, std::vector &end); +int findMaxLength(std::vector &nums, int target); + +int main() { + // std::vector nums = {3,4,1,7,8}; + // int target = 15; + // std::cout << findMaxLength(nums, target) << std::endl; + + std::string str = "01001001"; + + std::cout << findMaxLength(str) << std::endl; + + return 0; +} + +int findMaxGuests(std::vector &start, std::vector &end) +{ + if(start.size() != end.size()) return -1; + + int n = start.size(); + + sort(start.begin(), start.end()); + sort(end.begin(), end.end()); + + int i = 0, j = 0; + int count = 0, res = 0; + + while(i < n && j < n) + { + if(start[i] <= end[j]) { + res = std::max(res, ++count); + i++; + } + else { + count--; + j++; + } + } + + return res; +} + + +int findMaxLength(std::vector &nums, int target) +{ + std::unordered_map hash; + hash[0] = -1; + + int n = nums.size(); + int res = 0; + int sum = 0; + + for(int i = 0; i < n; i++) { + sum += nums[i]; + if(hash.count(sum-target)) res = std::max(res, i - hash[sum-target]); + hash[sum] = i; + } + + return res == 0 ? -1 : res; +} + +int findMaxLength(std::string &str) +{ + std::unordered_map hash; + hash[0] = -1; + + int n = str.size(); + int res = 0; + int sum = 0; + + for(int i = 0; i < str.size(); i++) { + if(str[i] == '0') sum += -1; + else if(str[i] == '1') sum += 1; + + if(hash.count(sum)) res = std::max(res, i - hash[sum]); + else hash[sum] = i; + } + + return res; +} + +class String +{ +private: + char *str; + size_t len; + +public: + String(const char *s = NULL) + { + if(s == NULL) { + str = new char[1]; + *str = '\0'; + len = 0; + } + else { + len = strlen(s); + str = new char[len+1]; + strcpy(str, s); + } + } + + //构造函数(深拷贝) + String(const String &demo) + { + len = demo.len; + str = new char[len+1]; + strcpy(str, demo.str); + } + + String& operator=(const String &demo) + { + if(this == &demo) return *this; + + delete[] str; + + len = demo.len; + str = new char[len+1]; + strcpy(str, demo.str); + + return *this; + } + + String operator+(const String &demo) const + { + int len = strlen(str) + strlen(demo.str) + 1; + char *sp = new char[len]; + strcpy(sp, str); + strcate(sp, demo.str); + + String tmp(sp); + return tmp; + } + + ~String() { + delete[] str; + } + +}; + + +void print1() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 1) { + cv.wait(lock); + } + + printf("A\n"); + sleep(1); + + k = 2; + cv.notify_all(); + } + +} + +void print2() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 2) { + cv.wait(lock); + } + + printf("B\n"); + sleep(1); + + k = 3; + cv.notify_all(); + } + +} + +void print3() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 3) { + cv.wait(lock); + } + + printf("C\n"); + sleep(1); + + k = 1; + cv.notify_all(); + } + +} + + + +#include +// #include +// #include +// #include +// #include +// #include + +int k = 1; + +std::condition_variable cv; +std::mutex mut; + +std::string s1 = "1234", s2 = "abcd"; + +void print1() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s1.size(); i++) + { + while(k != 1) cv.wait(lock); + + printf("%c\n", s1[i]); + // std::cout << s1[i] << std::endl; + + k = 2; + sleep(1); + + cv.notify_all(); + } + } + +} + +void print2() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s2.size(); i++) + { + while(k != 2) cv.wait(lock); + + printf("%c\n", s2[i]); + // std::cout << s2[i] << std::endl; + + k = 1; + sleep(1); + + cv.notify_all(); + } + } + +} + + +int main() { + // std::thread t1(print1), t2(print2); + + // t1.join(); + // t2.join(); + + std::vector nums = {0,1,2,3,4,5}; + + nums.erase(remove_if(nums.begin(), nums.end(), [](int x){ return x&1; }), nums.end()); + + for(auto &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + + +/* +#include +#include +#include +#include + +std::mutex mut; +std::condition_variable cv; + +int k = 0; //区分线程 + +std::string s1 = "abcd"; +std::string s2 = "1234"; + +void print1() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s1.size(); i++) + { + while(k != 0) cv.wait(lock); + std::cout << s1[i] << std::endl; + k = 1; + + sleep(1); //打印完暂停一秒看出变化 + + cv.notify_all(); + } + } + +} + +void print2() +{ + std::unique_lock lock(mut); + + while(1) + { + for(int i = 0; i < s2.size(); i++) + { + while(k != 1) cv.wait(lock); + std::cout << s2[i] << std::endl; + k = 0; + sleep(1); + cv.notify_all(); + } + } + +} + +int main() { + std::thread t1(print1), t2(print2); + + t1.join(); + t2.join(); + + return 0; +} + + +struct Node { + int data; + std::weak_ptr next; + + Node(int n): data(n) {} + ~Node() { + std::cout << "~Node()" << std::endl; + } +}; + + + +class Base { +public: + Base(): d(2) {} + virtual void print() { + std::cout << d << std::endl; + } + int d; +}; + +class Son : public Base { +public: + Son() : d(20) {} + void print() { + std::cout << d << std::endl; + } + int d; +}; + +int main() { + // Son *ptr = new Son(); + // Base *p = dynamic_cast(ptr); + + // p->print(); + + Base *p = new Son(); + Son *ptr = dynamic_cast(p); + + ptr->print(); + + return 0; +} + + +/* + 实现一个栈 + 支持三个操作:top取栈顶元素,pop弹出元素,max取栈中最大元素 +*/ +/* + +class myStack +{ +private: + std::vector nums, maxVal; + int end, size, index; + +public: + myStack(int n = 0) { + nums.resize(n); + maxVal.resize(n); + end = -1; + index = -1; + size = n; + } + + bool isFull() + { + if(end == size - 1) return true; + else return false; + } + + bool isEmpty() + { + if(end == -1) return true; + else return false; + } + + int top() + { + if(isEmpty()) return -1; + return nums[end]; + } + + void push(int x) + { + if(isFull()) return; + + nums[++end] = x; + + if(index == -1 || x > maxVal[index]) maxVal[++index] = x; + else { + int tmp = maxVal[index]; + maxVal[++index] = tmp; + } + } + + int max() + { + if(isEmpty()) return -1; + return maxVal[index]; + } + + void pop() + { + if(isEmpty()) return ; + --end; + --index; + } +}; + + +int main() { + myStack sta(10); + sta.push(1); + sta.push(3); + sta.push(1); + + while(!sta.isEmpty()) + { + std::cout << sta.max() << std::endl; + sta.pop(); + } + + // std::cout << sta.topNum() << std::endl; + + return 0; +} + + + + +class myQueue +{ +private: + int pre, tail, size; + std::vector nums; + +public: + myQueue(int n = 0) + { + nums.resize(n); + pre = tail = 0; + size = n; + } + + bool empty() + { + return pre == tail; + } + + bool full() + { + if((tail+1)%size == pre) return true; + return false; + } + + void push(int x) + { + if(full()) return; + nums[tail++] = x; + } + + void pop() + { + if(empty()) return; + + pre = (pre+1)%size; + } + + int front() + { + if(empty()) return -1; + return nums[pre]; + } + + int len() + { + return (tail-pre+size)%size; + } + +}; + + +int main() { + myQueue que(4); + que.push(1); + que.push(2); + que.push(3); + + while(!que.empty()) { + std::cout << que.front() << std::endl; + que.pop(); + } + + return 0; +} + + + +class Singleton +{ +private: + Singleton() {} + Singleton(Singleton const &); + Singleton& operator=(Singleton const &); + +public: + static Singleton& getInstance() { + static Singleton instance; + return instance; + } + +}; + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(Singleton const &); + +public: + static Singleton& getInstance() { + static Singleton instance; + return instance; + } +}; + + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + static Singleton *instance; + static std::mutex mut; + +public: + static Singleton* &getInstance() + { + if(instance == nullptr) + { + std::unique_lock lock(mut); + if(instance == nullptr) { + instance = new(std::nothrow) Singleton(); + } + } + + return instance; + } + +}; + +Singleton* Singleton::instance = nullptr; +std::mutex Singleton::mut; +*/ + +/* +#include +// #include + +// #define min(a,b) ((a) < (b) ? (a) : (b)) + +// #define swap(x, y) ({\ +// typeof(x) tmp = x;\ +// x = y;\ +// y = tmp;\ +// }) + +#define MIN(a, b) ({\ + typeof(a) x = a;\ + typeof(b) y = b;\ + x < y ? x : y;\ +}) + + +class Base +{ +public: + void print() { + std::cout << "base" << std::endl; + } +}; + +class Derived : public Base { +public: + void print() { + std::cout << "Derived" << std::endl; + } +}; + +/* +class A +{ +public: + A(){} + void destory() { + delete this; + } + +private: + ~A(){ + std::cout << "~A" << std::endl; + } + +}; +*/ +/* +class A +{ +protected: + A() { std::cout << "A" << std::endl; } + ~A() { std::cout << "~A" << std::endl; } + +public: + static A* create() { + return new A(); + } + + void destory() { + delete this; + } + +}; +*/ + +/* +class B { +public: + virtual void funB(){}; + int b; +}; + +class C { +public: + virtual void func(){}; + int c; +}; + +class A : public B, public C { +public: + virtual void funcA(){}; + int a; +}; + +void test(C *pc) { + pc->c = 9; +} +*/ + +/* +class A { +public: + virtual void print() {} +}; + +class B : public A { +public: + virtual void print() {} +}; + +class C : public A { +public: + virtual void print(){} +}; + + +class D : public B, public C { +public: + virtual void print() {} +}; + + +int findNum(std::vector &nums, int left, int right, int target) +{ + if(left > right) return -1; + + int mid = left + ((right-left) >> 1); + if(nums[mid] < target) { + return findNum(nums, mid + 1, right, target); + } + else if(nums[mid] > target) { + return findNum(nums, left, mid - 1, target); + } + + return mid; +} + + +void insertSort(std::vector &nums) +{ + for(int i = 1; i < nums.size(); i++) { + if(nums[i] < nums[i-1]) { + int tmp = nums[i]; + int j = i-1; + for(; j >= 0 && nums[j] >= tmp; j--) { + nums[j+1] = nums[j]; + } + nums[j+1] = tmp; + } + } + +} + + +void shellSort(std::vector &nums) +{ + int gap = nums.size(); + + do { + gap = gap/3 + 1; + + for(int i = gap; i < nums.size(); i++) { + if(nums[i] < nums[i-gap]) { + int tmp = nums[i]; + int j = i-gap; + for(; j >= 0 && nums[j] > tmp; j -= gap) { + nums[j+gap] = nums[j]; + } + nums[j+gap] = tmp; + } + } + } while(gap != 1); + +} + +void heapAdjust(std::vector &nums, int start, int end); + +void heapSort(std::vector &nums) +{ + int n = nums.size() - 1; + + for(int i = n/2; i >= 1; i--) { + heapAdjust(nums, i, n); + } + + for(int i = n; i > 1; i--) + { + std::swap(nums[i], nums[1]); + heapAdjust(nums, 1, i-1); + } + +} + + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j *= 2) + { + if(j < end && nums[j] < nums[j+1]) j++; + + if(tmp > nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; +} + + + + +int main() { + std::vector nums = {-1, 1,3, 2, 4, 6, 5}; + heapSort(nums); + + for(const int &n : nums) std::cout << n << " "; + std::cout << std::endl; + + // std::cout << findNum(nums, 0, 4, 5) << std::endl; + + // std::cout << sizeof(D) << std::endl; + // A *pA = new A(); + // C *pC = (C*)pA; + + // test(pC); + + // std::cout << pC->c << std::endl; + + // A *ptr = A::create(); + // ptr->destory(); + + // A *p = new A(); + // p->destory(); + // delete p; + + // Derived *p = new Derived(); + // Base *ptr = static_cast(p); + + // ptr->print(); + + // p->print(); + + // std::cout << min(1,2) << std::endl; + // int a = 1; + // float b = 2.2; + // swap(a, b); + // std::cout << a << " " << b << std::endl; + // std::cout << MIN(1, 2) << std::endl; + + return 0; +} +*/ + + + +/* +class MyVector +{ +private: + int *data; + int capacity; + int size; + + void addsize(int newsize) + { + int *newData = new int[newsize]; + for(int i = 0; i < size; i++) newData[i] = data[i]; + delete[] data; + + data = newData; + capacity = newsize; + } + +public: + MyVector() : data(nullptr), capacity(0), size(0) {} + + ~MyVector() { + delete[] data; + } + + MyVector(int m_size, int val = 0) + { + data = new int[m_size]; + memset(data, val, sizeof(data)); + capacity = m_size; + size = m_size; + } + + void push_back(int val) + { + if(capacity == size) { + addsize(2*size); + } + + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + int getsize() { + return size; + } + + int& operator[](int i) { + return data[i]; + } +}; + +int main() { + MyVector nums; + + // nums[0] = 1, nums[1] = 2, nums[2] = 3; + + // nums.push_back(4); + + int size = nums.getsize(); + + std::cout << size << std::endl; + + // for(int i = 0; i < size; i++) { + // std::cout << nums[i] << " "; + // } + // std::cout << std::endl; + + + return 0; +} + + + +template +class MyVector +{ +private: + T *data; + int capacity, size; + + void addsize(int newsize) + { + T *newData = new T[newsize]; + for(int i = 0; i < size; i++) newData[i] = data[i]; + delete[] data; + + data = newData; + capacity = newsize; + } + +public: + MyVector(): data(nullptr), capacity(0), size(0) {} + + MyVector(int m_size, T val = 0) + { + data = new T[m_size]; + // memset(data, val, sizeof(data)); + for(int i = 0; i < m_size; i++) data[i] = val; + + capacity = m_size; + size = m_size; + } + + MyVector(const MyVector &demo) + { + size = demo.size; + capacity = size; + data = new T[size]; + for(int i = 0; i < size; i++) data[i] = demo.data[i]; + } + + void push_back(int val) + { + if(capacity == size) { + addsize(2*size); + } + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + int getsize() { + return size; + } + + T& operator[](int i) { + return data[i]; + } +}; + + +int main() { + MyVector nums(3, 3); + + MyVector nums2(nums); + + int size = nums2.getsize(); + for(int i = 0; i < size; i++) { + std::cout << nums[i] << " "; + } + std::cout << std::endl; + + return 0; +} + + +class String +{ +private: + char *str; + size_t len; + +public: + String(const char *s = NULL) + { + if(s == NULL) { + str = new char[1]; + *str = '\0'; + len = 0; + } + else { + len = strlen(s); + str = new char[len+1]; + strcpy(str, s); + } + } + + String(const String &demo) + { + len = demo.len; + str = new char[len+1]; + strcpy(str, demo.str); + } + + String& operator=(const String &demo) + { + if(this == demo) return *this; + + delete[] str; + + len = demo.len; + str = new char[len+1]; + strcpy(str, demo.str); + + return *this; + } + + String operator+(const String &demo) const + { + int len = strlen(str) + strlen(demo.str) + 1; + char *sp = new char[len]; + strcpy(sp, str); + strcat(sp, demo.str); + String tmp(sp); + return tmp; + } + + ~String() { + delete[] str; + } + +}; + +#define MIN(a, b) ({\ + typeof(a) m_a = (a);\ + typeof(b) m_b = (b);\ + (m_x < m_y) ? m_a : m_b\ +}) + +*/ +// #include +// #include + + +//单例模式:懒汉式(返回全局对象的单例模式) + +/* +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + +public: + static Singleton& getInstance() { + static Singleton demo; + return demo; + } + + void print() { + std::cout << "hello" << std::endl; + } +}; +*/ + +/* +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + static Singleton *instance; + static std::mutex mut; + +public: + static Singleton* &getInstance() { + if(instance == nullptr) + { + std::unique_lock lock(mut); + if(instance == nullptr) { + instance = new(std::nothrow) Singleton(); + } + } + + return instance; + } + + void fun() { + std::cout << "hello" << std::endl; + } + +}; + +Singleton* Singleton::instance = nullptr; +std::mutex Singleton::mut; + + +int main() { + // Singleton &demo = Singleton::getInstance(); + // demo.print(); + Singleton* &ptr = Singleton::getInstance(); + ptr->fun(); + + return 0; +} +*/ + +/* +#include +#include + +// #define swap(x,y) ({\ +// x = x^y;\ +// y = x^y;\ +// x = x^y;\ +// }) + +// #define swap(x,y) ({\ +// x = x + y; \ +// y = x - y;\ +// x = x - y;\ +// }) + +#define swap(x, y) ({\ + typeof(x) tmp = x;\ + x = y;\ + y = tmp;\ +}) + + + +int main() { + int a = 1, b = 2; + + swap(a, b); + + std::cout << a << " " << b << std::endl; + + return 0; +} + + +void heapAdjust(std::vector &nums, int start, int end); +void heapSort(std::vector &nums); + +void mergeSort(std::vector &nums, int left, int right); +void merge(std::vector &nums, int left, int mid, int right); + +void quickSort(std::vector &nums, int left, int right); +int partition(std::vector &nums, int left, int right); + +int main() { + std::vector nums = {-1,9,1,5,8,3,7,4,6,2}; + + // heapSort(nums); + quickSort(nums, 0, nums.size() - 1); + + for(const int &n : nums) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + +void heapSort(std::vector &nums) +{ + int n = nums.size() - 1; + + for(int i = n/2; i >= 1; i--) { + heapAdjust(nums, i, n); + } + + for(int i = n; i > 1; i--) + { + std::swap(nums[1], nums[i]); + heapAdjust(nums, 1, i-1); + } + +} + +void heapAdjust(std::vector &nums, int start, int end) +{ + int tmp = nums[start]; + + for(int j = 2*start; j <= end; j *= 2) + { + if(j < end && nums[j] < nums[j+1]) j++; + + if(tmp > nums[j]) break; + + nums[start] = nums[j]; + + start = j; + } + + nums[start] = tmp; +} + + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right - left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, mid, right); + } + +} + +void merge(std::vector &nums, int left, int mid, int right) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right-left+1]; + int index = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] < nums[rindex]) { + team[index++] = nums[lindex++]; + } + else team[index++] = nums[rindex++]; + + } + + while(lindex <= mid) team[index++] = nums[lindex++]; + + while(rindex <= right) team[index++] = nums[rindex++]; + + for(int i = 0; i < index; i++) { + nums[left+i] = team[i]; + } + + delete[] team; +} + + +void quickSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = partition(nums, left, right); + quickSort(nums, left, mid); + quickSort(nums, mid + 1, right); + } + +} + +int partition(std::vector &nums, int left, int right) +{ + int pivot = nums[left]; + + while(left < right) + { + while(left < right && nums[right] >= pivot) right--; + std::swap(nums[left], nums[right]); + + while(left < right && nums[left] <= pivot) left++; + std::swap(nums[left], nums[right]); + } + + return left; +} + +std::vector findSubstring(std::string s, std::vector &words) +{ + std::vector res; + + if(s.empty() || words.empty()) return res; + + std::unordered_map mp; + for(auto &word : words) mp[word]++; + + int n = s.size(), num = words.size(), length = words[0].size(); + if(n < num*length) return res; + + for(int i = 0; i < length; i++) + { + int j = i; + while(j <= n-num*length) + { + int count = num; + std::unordered_map seen; + while(count > 0) { + std::string word = s.substr(j + (count-1)*length, length); + seen[word]++; + if(!mp.count(word) || seen[word] > mp[word]) break; + count--; + } + if(count == 0) res.push_back(j); + j += std::max(1, count)*length; + } + + } + + return res; +} + + +std::vector findSubstring(std::string s, std::vector &words) +{ + std::vector res; + + if(s.empty() || words.empty()) return res; + + std::unordered_map mp; + for(auto &word : words) mp[word]++; + + int n = s.size(), num = words.size(), length = words[0].size(); + if(n < length*num) return res; + + for(int i = 0; i < length; i++) + { + int j = i; + while(j <= n-num*length) + { + int count = 0; //统计以j开头的合格单词个数 + std::unordered_map seen; + while(count < num) + { + std::string word = s.substr(j + count*length, length); + seen[word]++; + if(!mp.count(word) || seen[word] > mp[word]) break; //如果以j开头的这个字符不在words中,或者出现次数大于words中单词出现次数,则跳出 + count++; + } + + if(count == num) res.push_back(j); //说明j是一个合格的位置 + j += std::max(1, count) * length; //细节,这里一定要取 max(1,count) + } + } + + return res; +} + +std::vector findSubstring(std::string s, std::vector &words) +{ + std::vector res; + + if(s.empty() || words.empty()) return res; + + std::unordered_map mp; + for(auto &word : words) mp[word]++; + + int n = s.size(), num = words.size(), length = words[0].size(); + + for(int i = 0; i <= n - num*length; i++) + { + std::unordered_map seen; + int count = 0; + while(count < num) + { + std::string word = s.substr(i + count*length, length); + seen[word]++; + if(!mp.count(word) || seen[word] > mp[word]) break; + count++; + } + + if(count == num) res.push_back(i); + } + + return res; +} + +class BitMap { +private: + std::vector vec; + +public: + BitMap(size_t size) { + vec.resize(size/32 + 1); + } + + bool set(size_t x) + { + if(x/32 > vec.size()) { + return false; + } + + size_t index = x/32; + size_t num = x%32; + + vec[index] |= (1 << num); + + return true; + } + + int find(size_t x) + { + if(x/32 > vec.size()) return -1; + + size_t index = x/32; + size_t num = x%32; + + return (vec[index] >> num) & 1; + } + + void clear() + { + vec.clear(); + } + +}; + +int count = 0; +int countNum(std::vector &nums, int target); +void dfs(std::vector &nums, int target, int pos); + +int main() { + std::vector nums = {1,3,5}; + int target = 100; + + countNum(nums, target); + + std::cout << count/2 << std::endl; + + return 0; +} + + +int countNum(std::vector &nums, int target) +{ + dfs(nums, target, 0); +} + +void dfs(std::vector &nums, int target, int pos) +{ + if(target == 0) { + count++; + return; + } + + if(target < 0) return; + + for(int i = pos; i < nums.size(); i++) { + dfs(nums, target - nums[i], i); + } + +} +std::mutex mut; +std::condition_variable cv; + +int k = 1; + +void printStirng1() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 1) cv.wait(lock); + + std::cout << "A" << std::endl; + + k = 2; + cv.notify_all(); + } + +} + +void printStirng2() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 2) cv.wait(lock); + + std::cout << "B" << std::endl; + + k = 3; + cv.notify_all(); + } + +} + +void printStirng3() +{ + std::unique_lock lock(mut); + + while(1) + { + while(k != 3) cv.wait(lock); + + std::cout << "C" << std::endl; + + k = 1; + cv.notify_all(); + } + +} + +int main() { + std::thread t1(printStirng1); + std::thread t2(printStirng2); + std::thread t3(printStirng3); + + t1.join(); + t2.join(); + t3.join(); + + return 0; +} + + +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode(int x) : val(x), left(NULL), right(NULL) {} +}; + + +std::string serialize(TreeNode *root) +{ + if(root == nullptr) return "#"; + + return std::to_string(root->val) + "," + serialize(root->left) + "," + serialize(root->right); +} + +TreeNode* deserialize(std::string data) +{ + std::stringstream in(data); + + return dfs(in); +} + +TreeNode* dfs(std::stringstream &in) +{ + std::string val; + getline(in, val, ','); + + if(val == "#") return nullptr; + + TreeNode *root = new TreeNode(std::stoi(val)); + root->left = dfs(in); + root->right = dfs(in); + + return root; +} + + +int main() { + TreeNode *root = new TreeNode(1); + root->right = new TreeNode(2); + + TreeNode *pRight = root->right; + pRight->right = new TreeNode(3); + + std::cout << serialize(root) << std::endl; + + return 0; +} + + +std::string lastSubstring(std::string s) +{ + char maxChar = 'a'; + for(const char &c : s) { + maxChar = std::max(maxChar, c); + } + + for(int i = 0; i < s.size(); i++) { + if(s[i] == maxChar) return s.substr(i); + } + + return ""; +} + + + +/* +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + +public: + static Singleton& getInstance() { + static Singleton instance; + return instance; + } + + void print() { + std::cout << "do something!" << std::endl; + } +}; +*/ + +// class Singleton +// { +// private: +// Singleton() {} +// Singleton(const Singleton &); +// Singleton& operator=(const Singleton &); +// static Singleton instance; + +// public: +// static Singleton& getInstance() { +// return instance; +// } + +// void print() { +// std::cout << "do something!" << std::endl; +// } + +// }; + +// Singleton::instance; + +/* +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton&); + Singleton& operator=(const Singleton&); + static Singleton *instance; + static std::mutex mut; + +public: + static Singleton* &getInstance() + { + if(instance == nullptr) + { + std::unique_lock lock(mut); + if(instance == nullptr) { + instance = new(std::nothrow) Singleton(); + } + } + return instance; + } + + void print() { + std::cout << "do something!" << std::endl; + } + +}; + +Singleton* Singleton::instance = nullptr; +std::mutex Singleton::mut; + + +// int main() { +// Singleton* &demo = Singleton::getInstance(); +// demo->print(); + +// return 0; +// } + +std::vector AA = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}; +std::vector BB = {"", "十", "百", "千", "万", "十万", "百万", "千万", "亿"}; + +std::string numberToChinese(int num) +{ + std::string res; + std::string numStr = std::to_string(num); + int k = numStr.size(); + + for(int i = 0; i < numStr.size(); i++) + { + int tmp = numStr[i] - '0'; + + if(tmp == 0) { + if(numStr[i-1] == '0' || i == numStr.size() - 1) continue; + else res += AA[tmp]; + } + else { + res += AA[tmp]; + if(numStr.size() == 2 && numStr[0] == '1' && i == 0) { + res.erase(0); //12读作十二,把1去掉 + } + res += BB[k-i-1]; + } + } + + return res; +} + + + + + +class myStack +{ +private: + std::vector nums, maxVal; + int size; //表示栈中元素大小 + int end; //表示nums栈顶元素位置 + int index; //表示maxVal栈顶元素位置 + +public: + myStack(int n = 0) { + nums.resize(n); + maxVal.resize(n); + end = -1; + index = -1; + size = n; + } + + bool isFull() { + if(end == size - 1) return true; + else return false; + } + + bool isEmpty() { + if(end == -1) return true; + else return false; + } + + int top() { + if(isEmpty()) return -1; + return nums[end]; + } + + void push(int x) + { + if(isFull()) return; + + nums[++end] = x; + + if(index == -1 || x > maxVal[index]) maxVal[++index] = x; + else { + int tmp = maxVal[index]; + maxVal[++index] = tmp; + } + } + + int max() { + if(isEmpty()) return -1; + return maxVal[index]; + } + + void pop() { + if(isEmpty()) return; + --end; + --index; + } +}; + + +class myQueue +{ +private: + int pre, tail, size; + std::vector nums; + +public: + myQueue(int n = 0) { + nums.resize(n); + pre = tail = 0; + size = n; + } + + bool empty() { + return pre == tail; + } + + bool full() { + if((tail+1)%size == pre) return true; + return false; + } + + void push(int x) { + if(full()) return ; + nums[tail] = x; + tail = (tail+1)%size; + } + + void pop() { + if(empty()) return; + pre = (pre+1)%size; + } + + int front() { + if(empty()) return -1; + return nums[pre]; + } + + int len() { + return (tail-pre+size)%size; + } +}; + +int main() { + myQueue que(3); + que.push(3); + que.push(1); + que.push(2); + + while(!que.empty()) { + std::cout << que.front() << std::endl; + que.pop(); + } + + + return 0; +} + + +void strcpy(char *des, char *src) +{ + if(des == nullptr || src == nullptr) return; + + char *pDes = des, *pSrc = src; + + while((*pDes++ = *pSrc) != '\0'); + +} + + +class String +{ +private: + char *str; + size_t len; + +public: + String(const char *s = NULL) + { + if(s == NULL) { + str = new char[1]; + *str = '\0'; + len = 0; + } + else { + len = strlen(s); + str = new char[len+1]; + strcpy(str, s); + } + } + + String(const String &demo) + { + len = demo.len; + str = new char[len+1]; + strcpy(str, demo.str); + } + + String& operator=(const String &demo) + { + if(this == &demo) return *this; + + delete[] str; + + len = demo.len; + str = new char[len+1]; + strcpy(str, demo.str); + + return *this; + } + + String operator+(const String &demo) const + { + int len = strlen(str) + strlen(demo.str) + 1; + char *sp = new char[len]; + strcpy(sp, str); + strcat(sp, demo.str); + String tmp(sp); + return tmp; + } + + ~String() { + delete[] str; + } + + void print() { + printf("%s\n", str); + } + +}; + + + + +template +class shared_ptr +{ +private: + T *ptr; + int *count; + +public: + shared_ptr(T *pointer = nullptr) + { + ptr = pointer; + + if(ptr == nullptr) count = new int(0); + else count = new int(1); + } + + shared_ptr(const shared_ptr &smartPtr) + { + ptr = smartPtr.ptr; + count = smartPtr.count; + + (*count)++; + } + + shared_ptr& operator=(const shared_ptr &smartPtr) + { + if(ptr != smartPtr.ptr) + { + if(ptr != nullptr && --(*count) == 0) { + delete ptr; + delete count; + } + + ptr = smartPtr.ptr; + count = smartPtr.count; + (*count)++; + } + } + + T& operator*() { return *ptr; } + + T* operator->() { return ptr; } + + ~shared_ptr() + { + if(ptr == nullptr) delete count; + else if(--(*count) == 0) { + delete ptr; + delete count; + } + } + + int use_count() { return *count; } + +}; + + + + +template +class MyVector +{ +private: + T *data; + int capacity, size; + + void addsize(int newsize) + { + T *newData = new T[newsize]; + for(int i = 0; i < size; i++) newData[i] = data[i]; + delete[] data; + + data = newData; + capacity = newsize; + } + +public: + MyVector() { + capacity = 1; //初始容量设置为1 + size = 0; + data = new int[capacity]; + } + + MyVector(int m_size, T val = 0) + { + data = new T[size]; + for(int i = 0; i < m_size; i++) data[i] = val; + + capacity = m_size; + size = m_size; + } + + MyVector(const MyVector &demo) + { + size = demo.size; + capacity = size; + data = new T[size]; + + for(int i = 0; i < size; i++) data[i] = demo.data[i]; + } + + ~MyVector() { + delete[] data; + } + + void push_back(int val) + { + if(size == capacity) addsize(2*size); + + data[size++] = val; + } + + void pop_back() { + if(size > 0) size--; + } + + T& operator[](int i) { + return data[i]; + } + + void print() { + std::cout << size << " " << capacity << std::endl; + } + +}; + + +int main() { + MyVector vec; + vec.push_back(9); + vec.push_back(3); + vec.push_back(1); + + std::cout << vec[0] << std::endl; + vec.print(); + + // int *data = new int[0]; + // data[0] = 1; + // data[1] = 2; + + // std::cout << data[1] << std::endl; + // delete[] data; + + return 0; +} +*/ + + + +// template +// struct ListNode { +// T val; +// ListNode *next; +// ListNode(int m_val) : val(m_val), next(nullptr) {} +// }; + +/* +template +int compare(const T &a, const T &b) { + if(std::less()(a, b)) return -1; + if(std::less()(a, b)) return 1; + return 0; +} + + +// class A { +// public: +// A(int m_val) : val(m_val) {} + +// private: +// int val; +// }; + +// class B { +// public: +// // B(A &m_a) { a(m_a); } +// B(A &m_a) : a(m_a) {} + +// private: +// A a; +// }; + +// class Base { +// public: +// Base() {} +// Base(int m_val) : val(m_val) {} +// int val; +// }; + +// class Derived : public Base { +// public: +// Derived(int m_val) : val(m_val) {} +// // Derived(int m_val) { val = m_val; } +// }; + + +class A { +public: + explicit A(int a) {} + explicit A(const A &a) {} +}; + + +int main() { + // ListNode node1 = ListNode(2.0); + // ListNode *pNode1 = new ListNode(2.0); + + // std::cout << compare(1,2) << std::endl; + + A a(1); + // A b = A(1); + A c = a; + + return 0; +} +*/ + +/* +class String +{ +private: + char *str; + size_t len; + +public: + String(const char *s = NULL) + { + if(s == NULL) { + str = new char[1]; + *str = '\0'; + len = 0; + } + else { + len = strlen(s); + str = new char[len + 1]; + strcpy(str, s); + } + } + + String(const String &demo) + { + len = demo.len; + str = new char[len + 1]; + strcpy(str, demo.str); + } + + String& operator=(const String &demo) + { + if(this = &demo) return *this; + + delete[] str; + + len = demo.len; + str = new char[len + 1]; + strcpy(str, demo.str); + + return *this; + } + + + //'+'运算符返回一个新的对象, + String operator+(const String &demo) const + { + int len = strlen(str) + strlen(demo.str) + 1; + char *sp = new char[len]; + strcpy(sp, str); + strcat(sp, demo.str); + String tmp(sp); + return tmp; + } + + ~String() { + delete[] str; + } + + void print() { + std::cout << str << std::endl; + } + +}; +*/ + +/* +class Student +{ +public: + int id, age; + + Student(int m_id, int m_age) : id(m_id), age(m_age) {} + + Student(int r) { + id = 1000; + age = r; + } + + Student operator+(const Student &demo) const + { + return Student(id + demo.id, age + demo.age); + } + +}; + +class A { +public: + A(int m_x) : x(m_x) {} + static void f(A a); + +private: + int x; +}; + +void A::f(A a) { + std::cout << a.x << std::endl; +} + +int main() { + // Student stu1(1, 100); + + // Student stu2 = stu1 + 111; + + // std::cout << stu2.id << " " << stu2.age << std::endl; + + + A demo(100); + + demo.f(demo); + // A::f(demo); + // A::f(demo); + + return 0; +} +*/ + + +/* +#include +#include +#include + +// template +// void add(T a, T b) { +// std::cout << "Version 1" << std::endl; +// } + +// template +// void add(const T &a, const T &b) { +// std::cout << "Version 2" << std::endl; +// } + +template +void debug(const T &t) { + std::cout << "Version 1" << std::endl; +} + + +template +void debug(T *p) { + std::cout << "Version 2" << std::endl; +} + +template +bool isPtr(T *p) { + return true; +} + +bool isPtr(...) { + return false; +} + +template +int compare(const T &a, const T &b) { + return a < b; +} + +template +int compare(const char(&a)[N], const char(&b)[M]) { + for(int i = 0; i < std::min(N, M); i++) { + if(a[i] == b[i]) continue; + else return a[i] < b[i]; + } + + return false; +} + + +int main() { + const char *p1 = "hi", *p2 = "mom"; + + // std::cout << compare(p1, p2) << std::endl; + std::cout << compare("hi", "mom") << std::endl; + + // int n1 = 1, n2 = 2; + // std::cout << add(1, 2) << std::endl; + + // add(1,2); + + // std::string s("hi"); + // debug(&s); + // debug(s.data()); + + // int n = 1; + // int *p = &n; + + // std::cout << isPtr(p) << std::endl; + // std::cout << isPtr(n) << std::endl; + + return 0; +} + + +int res = INT_MIN; + +int diameterOfBinary(TreeNode *root) +{ + if(root == nullptr) return 0; + + dfs(root); + + return res; +} + +void dfs(TreeNode *root) +{ + if(root == nullptr) return 0; + + int leftLen = dfs(root->left); + int rightLen = dfs(root->right); + + res = std::max(res, leftLen + rightLen); + + return std::max(leftLen, rightLen) + 1; +} +*/ + + +#include +#include + +/* +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + +public: + static Singleton& getInstance() { + static Singleton instance; + return instance; + } + + void printTest() { + std::cout << "do something!" << std::endl; + } + +}; +*/ + +class Singleton +{ +private: + Singleton() {} + Singleton(const Singleton &); + Singleton& operator=(const Singleton &); + static Singleton *instance; + static std::mutex mut; + +public: + static Singleton* &getInstance() + { + if(instance == nullptr) + { + std::unique_lock lock(mut); + if(instance == nullptr) { + instance = new(std::nothrow) Singleton(); + } + } + return instance; + } + + void print() { + std::cout << "do something!" << std::endl; + } + +}; + +Singleton* Singleton::instance = nullptr; +std::mutex Singleton::mut; + + +void strcmp(char *des, char *src) +{ + if(des == nullptr || src == nullptr) return; + + char *pDes = des, *pSrc = src; + + while((*pDes++ = *pSrc++) != '\0'); +} + + +int main() { + // Singleton& demo = Singleton::getInstance(); + // demo.printTest(); + + Singleton* demo = Singleton::getInstance(); + demo->print(); + + return 0; +} + + +void mergeSort(std::vector &nums, int left, int right) +{ + if(left < right) + { + int mid = left + ((right - left) >> 1); + mergeSort(nums, left, mid); + mergeSort(nums, mid + 1, right); + merge(nums, left, mid, right); + } + +} + +void merge(std::vector &nums, int left, int mid, int right) +{ + int lindex = left, rindex = mid + 1; + int *team = new int[right-left+1]; + int index = 0; + + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] <= nums[rindex]) { + team[index++] = nums[lindex++]; + } + else { + team[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) team[index++] = nums[lindex++]; + while(rindex <= right) team[index++] = nums[rindex++]; + + for(int i = 0; i < index; i++) { + nums[left+i] = team[i]; + } + + delete[] team; +} + + diff --git "a/\345\211\221\346\214\207Offer/dem01.cc" "b/\345\211\221\346\214\207Offer/dem01.cc" new file mode 100755 index 0000000..d4c7a04 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/dem01.cc" @@ -0,0 +1,67 @@ + +/* + 链表 P56 +*/ + +struct ListNode{ + int val; + ListNode *next; + +}; + + +//向链表末尾添加一个新节点 +void addToTail(ListNode **head, int value) +{ + ListNode *pNew = new ListNode(); + pNew->val = value; + pNew->next = nullptr; + + if(*head == nullptr){ + *head = pNew; + } + else{ + ListNode *pNode = *head; + while(pNode->next != nullptr){ + pNode = pNode->next; + } + pNode->next = pNew; + + } + +} + + + +//在链表中找到第一个含有某值的节点并删除该节点 + +void removeNode(ListNode **head, int value) +{ + if(head == nullptr || *head == nullptr) return; //空链表直接返回 + + ListNode *pToBeDeleted = nullptr; + + if((*head)->val == value){ //头指针就是要删除的节点 + pToBeDeleted = *head; + *head = *head->next; + } + else{ + ListNode *pNode = *head; + while(pNode->next != nullptr && pNode->next->val != value){ + pNode = pNode->next; + } + if(pNode->next != nullptr && pNode->next->val == value){ + pToBeDeleted = p->next; + pNode->next = pNode->next->next; + } + + } + + if(pToBeDeleted != nullptr){ //表示找到了待删除节点 + delete pToBeDeleted; //如果链表中没找到要删除的节点,则不做任何操作 + pToBeDeleted = nullptr; + } + +} + + diff --git "a/\345\211\221\346\214\207Offer/dem02.cc" "b/\345\211\221\346\214\207Offer/dem02.cc" new file mode 100755 index 0000000..c9aeb21 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/dem02.cc" @@ -0,0 +1,39 @@ + +//P81 +//实现一个时间复杂度为O(n)的排序算法 + +void sortAges(int ages[], int length) +{ + if(ages == nullptr || length < 0) return; + + const int oldestAge = 99; //年龄范围为0~99 + int timeOfAge[oldestAge+1]; //存储某个年龄出现的次数 + + for(int i = 0; i <= oldestAge; i++) + { + //初始化数组,每个元素赋值为0 + timeOfAge[i] = 0; + } + + for(int i = 0; i < length; i++) + { + int age = ages[i]; + if(age < 0 || age > oldestAge) { + std::cout << "Error:age out of range."; + exit(1); + } + timeOfAge[age]++; //timeOfAge里面存储的是每个年龄出现的次数 + } //如timeOfAge[1]=2,代表年龄1出现了2次; timeOfAge[4]=3,代表年龄4出现了3次 + //有些年龄不出现,就是0,如timeOfAge[0]=0,代表年龄0出现了0次,那么排序的时候就会跳过该年龄 + + int index = 0; + for(int i = 0; i <= oldestAge; i++) + { + for(int j = 0; j < timeOfAge[i]; j++) + { + ages[index] = i; + ++index; + } + } + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex1.cc" "b/\345\211\221\346\214\207Offer/ex1.cc" new file mode 100755 index 0000000..d264d15 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex1.cc" @@ -0,0 +1,45 @@ + + +//1.实现赋值运算符函数 + +class CMyString +{ +public: + CMyString(char *pData = nullptr); + CMyString(const CMyString &str); + ~CMyString(); + +private: + char *m_pData; + +}; + +//第一种解法 +CMyString& CMyString::operator=(const CMyString &str) +{ + if(this != &str) + { + delete[] m_pData; + m_pData = nullptr; + + m_pData = new char[strlen(str) + 1]; //存在一个隐患,如果分配内存失败,则是会抛出异常的 + strcpy(m_pData, str.m_pData); //则m_pData是一个空指针,这样非常容易导致程序崩溃 + } //也即CMyString的实例也不存在了,在申请内存之前释放掉了 + + return *this; +} + +//第二种写法:考虑线程安全 +CMyString& CMyString::operator=(const CMyString &str) +{ + if(this != &str) + { + CMyString strTmp(str); //先申请一个临时对象申请够足够的内存,如果程序崩溃了原对象还存在 + + char *pTmp = strTmp.m_pData; + strTmp.m_pData = m_pData; //strTmp的m_pData指向的是实例之前的内存,所以相当于自动调用析构函数释放内存 + m_pData = pTmp; + } + + return *this; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex10.cc" "b/\345\211\221\346\214\207Offer/ex10.cc" new file mode 100755 index 0000000..35fc092 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex10.cc" @@ -0,0 +1,31 @@ +//面试题10 +//Fibonacci数列 + 青蛙跳台阶问题 + +#include + +long Fibonacci(int n); + +int main(){ + int n = 100; + std::cout << Fibonacci(n) << std::endl; //代表求F(3)的值, F(0)=0, F(1)=1, F(2)=1 + + return 0; +} + + +long Fibonacci(int n) +{ + int result[2]= {0, 1}; + + if(n < 2) return result[n]; + + long left = 0, right = 1; + long target; + for(int i = 2; i <= n; i++){ + target = left + right; + left = right; + right = target; + } + + return target; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex11.cc" "b/\345\211\221\346\214\207Offer/ex11.cc" new file mode 100755 index 0000000..978f299 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex11.cc" @@ -0,0 +1,57 @@ +//面试题11 +//寻找旋转数组的最小数字 + +//思路:二分查找 + + +#include + +int minOrder(int *numbers, int low, int hig); +int min(int *numbers, int length); + +int main(){ + int num[] = {1,0,1,1,1}; + std::cout << min(num,5) << std::endl; + + return 0; +} + + +int min(int *numbers, int length) +{ + if(numbers == nullptr || length <= 0) return -1; //失败返回-1 + + int low = 0, hig = length-1; + int mid = low; + + while(numbers[low] >= numbers[hig]){ + if(hig-low == 1){ + mid = hig; + break; + } + mid = (low+hig)/2; + + if(numbers[low]==numbers[hig] && numbers[low]==numbers[mid]){ //首位末位和中间位相等时只能采用顺序查找 + return minOrder(numbers, low, hig); + } + + if(numbers[mid] >= numbers[low]) low = mid; //说明中间位置数位于左半部分 + + else if(numbers[mid] <= numbers[hig]) hig = mid; //说明中间位置数位于右半部分 + + } + + return numbers[mid]; + +} + + +int minOrder(int *numbers, int low, int hig){ + int result = numbers[low]; + for(int i = low+1; i <= hig; i++){ + if(result > numbers[i]) result = numbers[i]; + } + + return result; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex12.cc" "b/\345\211\221\346\214\207Offer/ex12.cc" new file mode 100755 index 0000000..204ee3c --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex12.cc" @@ -0,0 +1,43 @@ + +//面试题12 : 矩阵中的路径 + +//参考Leetcode第79题 + + +bool hasPath(char* matrix, int rows, int cols, char *str) +{ + if(matrix == nullptr || rows < 1 || cols < 1 || str == nullptr) return false; + + // bool *visited = new bool[rows*cols]; //不需要额外定义一个数组 + // memset(visited, 0, rows*cols); + + int pathLength = 0; + for(int row = 0; i < rows; i++){ + for(int col = 0; j < cols; j++){ + if(hasPathCore(matrix, rows, cols, row, col, str, pathLength)) return true; + } + } + + // delete[] visited; + + return false; + +} + + +bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, int &pathLength, bool* visited){ + if(str[pathLength] == '\0') return false; + + if(row < 0 || row > rows-1 || col < 0 || col > cols-1 || matrix[row*cols+col] != str[pathLength]) return false; //越过了边界,直接返回false; + + char cur = matrix[row*cols+col]; + matrix[row*cols+col] = '*'; + bool search_next = hasPathCore(matrix, rows, cols, row-1, col, pathLength+1) + ||hasPathCore(matrix, rows, cols, row, col+1, pathLength+1) + ||hasPathCore(matrix, rows, cols, row+1, col, pathLength+1) + ||hasPathCore(matrix, rows, cols, row, col-1, pathLength+1); + matrix[row*cols+col] = cur; + + return search_next; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex13.cc" "b/\345\211\221\346\214\207Offer/ex13.cc" new file mode 100755 index 0000000..a0ea393 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex13.cc" @@ -0,0 +1,78 @@ + +//面试题13 : 机器人的运动范围 + + +#include +#include + +int movingCount(int threshold, int rows, int cols); +int movingCountCore(int threshold, int rows, int cols, int row, int col, bool *visited); +bool check(int threshold, int rows, int cols, int row, int col, bool *visited); +int getDigitSum(int num); + + +int main(){ + + std::cout << movingCount(5, 10, 10) <= 0 && row < rows && col >= 0 && col < cols && getDigitSum(row) + getDigitSum(col) <= threshold && !visited[row*cols+col]){ + return true; + } + + return false; + +} + + +int getDigitSum(int number){ + int sum = 0; + while(number > 0){ + sum += number%10; + number /= 10; + } + + return sum; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex14.cc" "b/\345\211\221\346\214\207Offer/ex14.cc" new file mode 100755 index 0000000..e69dd37 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex14.cc" @@ -0,0 +1,113 @@ + + +/* + 面试题14:减绳子 (Leetcode第343题) + 要求至少减一刀,也就至少要有两段绳子 +*/ + + +//动态规划 + +int maxProductAfterCutting_Solution1(int length) +{ + //如果输入的数值是这几个,直接就返回结果 + if(length < 2) return 0; + if(length == 2) return 1; + if(length == 3) return 2; + + //注意:由公式f(n) = max(f(i)*f(n-i)) 0=4 , 其中product存储的就是f(i),即prodcut[i]=f(i) + int *products = new int[length + 1]; + products[0] = 0; + products[1] = 1; + products[2] = 2; + products[3] = 3; + + for(int i = 4; i <= length; i++) + { + int max = 0; + for(int j = 1; j <= i/2; j++) + { + int prod = products[j] * products[i-j]; + if(max < prod) { + max = prod; + } + + products[i] = max; + } + } + + int ans = products[length]; + + delete[] products; + + return ans; +} + + +//C++解法 +int integerBreak(int n) +{ + if(n <= 1) return 0; + if(n == 2) return 1; + if(n == 3) return 2; + + std::vector dp(n+1, 0); + + //这里的dp[i]不是代表总长度长度为i的绳子能减出的最大长度 + //这里的dp[i]代表的是剪出长度为i的子绳子的最大长度,就是f(i) + dp[1] = 1, dp[2] = 2, dp[3] = 3; + + for(int i = 4; i <= n; i++) + { + int maxVal = 0; + for(int j = 2; j <= i/2; j++) { + maxVal = std::max(maxVal, dp[j]*dp[i-j]); + } + dp[i] = maxVal; + } + + return dp[n]; +} + + +//贪婪算法 + +int maxProductAfterCutting_Solution2(int length) +{ + if(length < 2) return 0; + if(length == 2) return 1; + if(length == 3) return 2; + + //尽可能多的去减长度为3的绳子 + int timesOf3 = length/3; + + //当绳子剩下的长度为4的时候,不能再去减长度为3的绳子 + if(length - timesOf3*3 == 1) { + timesOf3 -= 1; + } + + int timesOf2 = (length - timesOf3*3) / 2; + + return (int)pow(3, timesOf3) * (int)pow(2, timesOf2); +} + + +//贪婪算法:求出最多的3即可 +//当n>=5时,竟可能多的去减长度为3的绳子 +//当n=4时,剪成长度为2的两根绳子,乘积还是4 + +int integerBreak(int n) +{ + if(n <= 1) return 0; + if(n == 2) return 1; + if(n == 3) return 2; + + int res = 1; + while(n > 4) + { + res *= 3; + n -= 3; + } + + return res*n; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex15.cc" "b/\345\211\221\346\214\207Offer/ex15.cc" new file mode 100755 index 0000000..fb6b111 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex15.cc" @@ -0,0 +1,83 @@ + +/* + 面试题15:二进制中1的个数 +*/ + +//思路:一个整数减去1,在和原整数做与运算就会把该整数的最右边的1变成0; +//这种方法整数中有几个1就只需要循环几次 + +#include + + +int NumberOf1_1(int n); +int NumberOf1_2(int n); + + +int main(){ + //计算机中的数据都是以补码表示的,-2原码为:10000000 0000000 00000000 00000010 + //反码为:11111111 1111111 11111111 11111101 补码为:11111111 11111111 11111111 11111110 所以输出结果为31 + + // std::cout << NumberOf1_2(-2) << std::endl; + + std::cout << NumberOf1_2(9) << std::endl; + + return 0; +} + + + +//常规解法(暴力解法) +int NumberOf1_1(int n) +{ + int count = 0; + int flag = 1; + + while(flag){ + if(n&flag) count++; + flag = flag<<1; + } + + return count; +} + + +//利用减去1的数和原整数做与运算 +int NumberOf1_2(int n) +{ + int count = 0; + + while(n){ + count++; + n = (n-1)&n; + } + + return count; +} + + + + +//相关题目一:用一条语句判断一个整数是否为2的整数次方 + +bool isPowerOf2(int n) +{ + return n&(n-1) == 0; +} + + + +//相关题目二:输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n +//1.先计算这两个数的异或; 2.统计异或结果中的1的个数 + +int mTon(int m, int n) +{ + int count = 0; + + int tmp = m^n; + whie(tmp) { + count++; + tmp = (tmp)&(tmp-1); + } + + return count; +} diff --git "a/\345\211\221\346\214\207Offer/ex16.cc" "b/\345\211\221\346\214\207Offer/ex16.cc" new file mode 100755 index 0000000..ed904a9 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex16.cc" @@ -0,0 +1,105 @@ + + +/* + 面试题16:实现pow函数 +*/ + + +#include + +double power(double base, int exponent); +bool equal(double num1, double num2); +double powerWithUnsignedExponent(double base, unsigned int exponent); + + +int main(){ + std::cout << power(2.2, 2) << std::endl; + + return 0; +} + + +double power(double base, int exponent) +{ + //如果底数为0并且指数小于0则打印错误信息,并返回一个0.0 + if(equal(base, 0.0) && exponent < 0) + { + printf("Input Error!\n"); + return 0.0; + } + + //如果底数为0,但指数大于等于0,则直接返回0.0 + else if(equal(base, 0.0)) + { + return 0.0; + } + + else + { + unsigned int absExponent = (unsigned int)(exponent); + if(exponent < 0) { + absExponent = (unsigned int)(-exponent); + } + + double result = powerWithUnsignedExponent(base, absExponent); + + if(exponent < 0) { + result = 1.0/result; + } + + return result; + + } + +} + + +//判断两个浮点数是否相等 +bool equal(double num1, double num2) +{ + if(num1-num2 <= 0.00001 && num1-num2 > -0.00001) { + return true; + } + else { + return false; + } + +} + + +//计算幂乘 +double powerWithUnsignedExponent(double base, unsigned int exponent) +{ + double result = 1.0; + for(int i = 1; i <= exponent; i++) { + result *= base; + } + + return result; + +} + + +//优化上面做幂乘的函数 +double powerWithUnsignedExponent(double base, unsigned int exponent) +{ + if(exponent == 0) { + return 1.0; + } + if(exponent == 1) { + return base; + } + + double result = powerWithUnsignedExponent(base, exponent >> 1); + result *= result; + + //利用位与运算符来判断一个数是奇数还是偶数 + if(exponent & 0x1 == 1) { + result *= base; + } + + return result; + +} + + diff --git "a/\345\211\221\346\214\207Offer/ex17.cc" "b/\345\211\221\346\214\207Offer/ex17.cc" new file mode 100755 index 0000000..ac6362d --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex17.cc" @@ -0,0 +1,81 @@ + + +/* + 面试题17:打印从1到最大的n位数 + 陷阱题 +*/ + +//可以使用递归和非递归两种方法 +//非递归方法比较难想到 + + +#include +#include + +void printNumber(char *number); +void print1ToMaxOfNDigits(int n); +void print1ToMaxOfNDigitsRecursively(char *number, int length, int index); + + +int main(){ + + print1ToMaxOfNDigits(3); + + return 0; +} + + +void print1ToMaxOfNDigits(int n) +{ + if(n <= 0) return; + + char *number = new char[n+1]; + number[n] = '\0'; + + for(int i = 0; i < 10; i++) + { + number[0] = i + '0'; + print1ToMaxOfNDigitsRecursively(number, n, 0); + } + + delete[] number; + +} + +void print1ToMaxOfNDigitsRecursively(char *number, int length, int index) +{ + if(index == length-1) + { + printNumber(number); + return; //注意:递归一定要有出口,也就是一定要有return语句 + } + + for(int i = 0; i < 10; i++) + { + number[index+1] = i + '0'; //注意:数字第一位数字的递增在这里设置 + print1ToMaxOfNDigitsRecursively(number, length, index+1); + } + +} + + +void printNumber(char *number) +{ + bool isBeginning0 = true; + int length = strlen(number); + + for(int i = 0; i < length; i++) + { + if(number[i] != '0') { //这里可以不必加isBeginning0这个条件 + isBeginning0 = false; + } + + if(!isBeginning0) { + printf("%c", number[i]); + } + + } + + printf("\t"); + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex18.cc" "b/\345\211\221\346\214\207Offer/ex18.cc" new file mode 100755 index 0000000..1d87abb --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex18.cc" @@ -0,0 +1,72 @@ + + +/* + 面试题18:删除链表的节点 + + 1.给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点 + + 2.删除链表中重复的节点:提供的解法不太好,参考Leetcode第83题和第84题 + +*/ + + +struct ListNode { + int val; + ListNode *next; +}; + + + +//1.给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点 + +//思路:给定了要删除的节点指针,需要在O(1)时间内完成删除操作 +//我们将要删除节点i的下一个节点j的内容复制给i,然后把i的指针指向j的下一个节点 +//然后再删除节点j,其效果刚好就是把节点i删除了 + +//需要注意:当删除节点不是不是尾节点是就按上述方法进行 +//当链表只有一个元素,则需要删除头结点,并将链表置空 +//当链表有多个元素,但是删除节点是尾节点,这时只能使用顺序遍历到要删除节点的前一个节点,时间复杂度为O(n) + + + +void deleteNode(ListNode **pListHead, ListNode *pToBeDeleted) +{ + if(pListHead == nullptr || pToBeDeleted == nullptr) return; + + //要删除的节点不是尾节点 + if(pToBeDeleted->next != nullptr) + { + ListNode *pNext = pToBeDeleted->next; + pToBeDeleted->val = pNext->val; + pToBeDeleted->next = pNext->next; + + delete pNext; + pNext = nullptr; //防止成为悬空指针 + + } + + //要删除的节点是尾节点,但是链表只有一个节点,删除尾节点(也是头节点) + else if(*pListHead == pToBeDeleted) + { + delete pToBeDeleted; + pToBeDeleted = nullptr; + *pListHead = nullptr; + + } + + //要删除的节点是尾节点,而且链表有多个节点 + else + { + ListNode *pNode = *pListHead; + while(pNode->next != pToBeDeleted) { + pNode = pNode->next; //找到删除节点的前一个节点 + } + + pNode->next = nullptr; + + delete pToBeDeleted; + pToBeDeleted = nullptr; + + } + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex19.cc" "b/\345\211\221\346\214\207Offer/ex19.cc" new file mode 100755 index 0000000..c36eb80 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex19.cc" @@ -0,0 +1,110 @@ + + +/* + 面试题18:正则表达式匹配 + //注意:只有模式里才有'.'和'*'符号; 而字符串中是没有这两个符号的 +*/ + + +//思路:重点在于模式中第二个字符就为'*' +//如果模式中第二个字符就是'*',有以下两种情况 +//1.在模式上直接后移两个字符,相当于'*'和它前面的字符被忽略了 +//2.如果字符串的第一个字符和模式的第一个字符相匹配,则将字符串后移一个元素 +// 而在模式上有两种选择:(1).可以在模式上向后移动两个字符 (2).也可以保持模式不变 +// 或者像1一样,直接忽略掉该'*',字符串也不向后移 + +//注意:上面的思路利用的是递归,在Leetcode第10题这种写法会提示超时 +//改用动态规划会更加简洁 + + +#include + +bool match(char *str, char *pattern); +bool matchCore(char *str, char *pattern); + +int main(){ + char str[] = "aaa"; + char pattern[] = "a.a"; + std::cout << match(str, pattern) << std::endl; + + return 0; +} + +bool match(char *str, char *pattern) +{ + if(str == nullptr || pattern == nullptr) return false; + + return matchCore(str, pattern); + +} + +bool matchCore(char *str, char *pattern) +{ + //如果字符串匹配到了模式末尾字符,则说明匹配成功 + if(*str == '\0' && *pattern == '\0') return true; + + //到了模式末尾却没到字符串末尾,则说明匹配失败(注意:这句话不能省) + if(*str != '\0' && *pattern == '\0') return false; + + //如果模式首元素是就是'*'则肯定匹配失败,所以这里从模式第二个元素开始判断 + if(*(pattern + 1) == '*') + { + if(*pattern == *str || (*pattern == '.' && *str != '\0')) { + return matchCore(str + 1, pattern + 2) || + matchCore(str + 1, pattern) || + matchCore(str, pattern + 2); + } + else + { //如果'*'前面的字符都没有匹配成功,则后面的'*'只能表示前面的字符出现了0次,直接后移两位到'*'后面的字符 + return matchCore(str, pattern + 2); + } + + } + + //第二个字符不是'*',且第一个字符匹配成功则字符串和模式都后移一位 + if(*str == *pattern || (*pattern == '.' && *str != '\0')) { + return matchCore(str + 1, pattern + 1); + } + + return false; //其他情况返回false +} + + + +//利用string的写法 + +bool match(std::string str, std::string pattern) +{ + //这个边界条件不能这么写,比如 str="", patten=".*"这也表示匹配成功 + // if(str.empty() || pattern.empty()) return false; + + return matchCore(str, 0, pattern, 0); +} + + +bool matchCore(std::string str, int i, std::string pattern, int j) +{ + if(i >= str.size() && j >= pattern.size()) return true; + + if(i < str.size() && j >= pattern.size()) return false; + + if(pattern[j+1] == '*') + { + if(str[i] == pattern[j] || (pattern[j] == '.' && i < str.size())) { + return matchCore(str, i + 1, pattern, j + 2) || + matchCore(str, i + 1, pattern, j) || + matchCore(str, i, pattern, j + 2); + } + else + { + return matchCore(str, i, pattern, j + 2); + } + + } + + if(str[i] == pattern[j] || (pattern[j] == '.' && i < str.size())) { + return matchCore(str, i + 1, pattern, j + 1); + } + + return false; +} diff --git "a/\345\211\221\346\214\207Offer/ex2.cc" "b/\345\211\221\346\214\207Offer/ex2.cc" new file mode 100755 index 0000000..6c5042f --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex2.cc" @@ -0,0 +1,63 @@ + + +/* + 面试题52:两个链表的第一个公共节点 +*/ + + +//思路:先得到两个链表的长度 +//让长链表先多走几步走到和短链表相同的起点,之后长短链表同时出发,直到走到公共节点 + +struct ListNode{ + int key; + ListNode *next; +}; + +ListNode* findFirstCommonNode(ListNode *pHead1, ListNode *pHead2) +{ + //得到两个链表的长度 + unsigned int nLength1 = getListLength(pHead1); + unsigned int nLength2 = getListLength(pHead2); + int nLengthDif = nLength1-nLength2; + + ListNode *pListHeadLong = pHead1; + ListNode *pListHeadShort = pHead2; + if(nLength2 > nLength1) + { + pListHead1 = pHead2; + pListHeadShort = pHead1; + nLengthDif = nLength2-nLength1; + } + + //先在长链表上走几步,再同时在两个链表上遍历 + for(int i = 0; i < nLengthDif; i++) { + pListHeadLong = pListHeadLong->next; + } + + while((pListHeadLong != nullptr) && (pListHeadShort != nullptr) && (pListHeadShort != pListHeadLong)) + { + pListHeadLong = pListHeadLong->next; + pListHeadShort = pListHeadShort->next; + } + + ListNode *pFirstCommonNode = pListHeadLong; + + return pFirstCommonNode; + +} + + +//计算链表的长度 +unsigned int getListLength(ListNode *pHead) +{ + unsigned int nLength = 0; + ListNode *pNode = pHead; + + while(pNode != nullptr) { + ++nLength; + pNode = pNode->next; + } + + return nLength; + +} diff --git "a/\345\211\221\346\214\207Offer/ex20.cc" "b/\345\211\221\346\214\207Offer/ex20.cc" new file mode 100755 index 0000000..c87ad1c --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex20.cc" @@ -0,0 +1,120 @@ + + +/* + 面试题20:表示数值的字符串 + 弄清楚怎么表示一个正确的数值 +*/ + + +#include + +bool isNumeric(const char *str); +bool scanUnsignedInteger(const char **str); +bool scanInteger(const char **str); + + +int main(){ + char str[] = ""; + + std::cout << isNumeric(str) << std::endl; + + return 0; +} + + +bool isNumeric(const char *str) +{ + if(str == nullptr) return false; + + bool numeric = scanInteger(&str); + + if(*str == '.') { + ++str; + numeric = scanUnsignedInteger(&str) || numeric; + } + + if(*str == 'e' || *str == 'E') { + ++str; + numeric = scanInteger(&str) && numeric; + } + + return numeric && *str == '\0'; + +} + + +bool scanUnsignedInteger(const char **str) +{ + const char *before = *str; + + while(**str != '\0' && **str >= '0' && **str <= '9') { + ++(*str); + } + + return *str > before; + +} + + +bool scanInteger(const char **str) +{ + if(**str == '+' || **str == '-') { + ++(*str); + } + + return scanUnsignedInteger(str); +} + + +//C++的解法 + +//匹配模式为 A[.[B]][e|EC] +//由于小数点前可能为空,如果为空,则小数点后一定要有数子 .B[e|Ec] +//[]代表可选项,可以没有,其中A和C都代表可能以'+'或者'-'开头的数字,而B不可能以符号开头 + +bool isNumber(std::string s) +{ + if(s.empty()) return false; + + int i = 0; + bool numeric = scanInteger(s, i); //扫描A部分 + + //扫描B部分 + if(s[i] == '.') { + i++; + numeric = scanUnsignedInteger(s, i) || numeric; //注意这里是或,小数点前面或者后面可能没有数字 + } + + //扫描C部分 + if(s[i] == 'E' || s[i] == 'e') { + i++; + numeric = numeric && scanInteger(s, i); //注意:这里是用与,因为e前面必须要求有数字 + } + + return numeric && (i == s.size()); //判断是否到达了字符串末尾 +} + +bool scanInteger(std::string s, int &i) +{ + if(i >= s.size()) return false; + + if(s[i] == '+' || s[i] == '-') i++; + + return scanUnsignedInteger(s, i); +} + +bool scanUnsignedInteger(std::string s, int &i) +{ + if(i >= s.size()) return false; + + int before = i; + + while(i < s.size()) + { + if(s[i] >= '0' && s[i] <= '9') i++; + else break; + } + + //s中存在无符号数时才返回 + return i > before; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex21.cc" "b/\345\211\221\346\214\207Offer/ex21.cc" new file mode 100755 index 0000000..5d3c1b2 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex21.cc" @@ -0,0 +1,113 @@ + + +/* + 面试题21:调整数组顺序使奇数位于偶数前面 + 使用双指针 +*/ + + +#include + +void reorderOddEven(int *pData, unsigned int length); +void reorderOddEven(int *pData, unsigned int length, bool(*func)(int)); +bool isEven(int n); +bool isPositive(int n); +bool isNotMultipleOf3(int n); + + +int main(){ + int num[] = {1,2,3,6,-5}; + int len = sizeof(num)/sizeof(num[0]); + + reorderOddEven(num, len, isNotMultipleOf3); + + for(int n:num) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + + +//方法一:利用双指针法 + +void reorderOddEven(int *pData, unsigned int length) +{ + if(pData == nullptr || length == 0) return; + + int *pBegin = pData; + int *pEnd = pData + length - 1; + + //偶数都放到后面 + while(pBegin < pEnd) + { + //向后移动pBegin,直到它指向偶数 + while(pBegin < pEnd && (*pBegin & 0x1) != 0) { + pBegin++; + } + + //向前移动pEnd,直到它指向奇数 + while(pBegin < pEnd && (*pEnd & 0x1) == 0) { + pEnd--; + } + + //将两指针指向的数交换 + if(pBegin < pEnd) { + int temp = *pBegin; + *pBegin = *pEnd; + *pEnd = temp; + } + + } + +} + + + +//对上面代码的优化 + +void reorderOddEven(int *pData, unsigned int length, bool(*func)(int)) +{ + if(pData == nullptr || length == 0) return; + + int *pBegin = pData; + int *pEnd = pData + length - 1; + + while(pBegin < pEnd) + { + while(pBegin < pEnd && !func(*pBegin)) { + pBegin++; + } + + while(pBegin < pEnd && func(*pEnd)) { + pEnd--; + } + + if(pBegin < pEnd) { + int temp = *pBegin; + *pBegin = *pEnd; + *pEnd = temp; + } + + } + +} + + +bool isEven(int n) +{ + return (n & 1) == 0; +} + + +bool isPositive(int n) +{ + return n > 0; +} + + +bool isNotMultipleOf3(int n) +{ + return (n % 3) != 0; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex22.cc" "b/\345\211\221\346\214\207Offer/ex22.cc" new file mode 100755 index 0000000..6146cf7 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex22.cc" @@ -0,0 +1,44 @@ + + + +/* + 面试题22:链表中的倒数第k个节点 + 利用快慢指针 +*/ + + +struct ListNode{ + int value; + ListNode *next; +}; + + +ListNode *findKthToTail(ListNode *pListHead, unsigned int k) +{ + if(pListHead == nullptr || k == 0) return nullptr; + + ListNode *pAhead = pListHead; + ListNode *pBehind = pListHead; + + //快指针先走k-1步 + for(unsigned int i = 0; i < k-1; i++) + { + if(pAhead->next != nullptr) { + pAhead = pAhead->next; + } + else { + return nullptr; + } + + } + + //快指针走了k-1步后,快慢指针同时出发 + while(pAhead->next != nullptr) + { + pAhead = pAhead->next; + pBehind = pBehind->next; + } + + return pBehind; + +} diff --git "a/\345\211\221\346\214\207Offer/ex23.cc" "b/\345\211\221\346\214\207Offer/ex23.cc" new file mode 100755 index 0000000..d44c858 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex23.cc" @@ -0,0 +1,69 @@ + + + +/* + 面试题23:链表中环的入口节点 + 与Leetcode第142题相同,推荐使用Leetcode解法,比这个更加简洁 +*/ + + +//在链表中存在环的前提下找到一快一慢指针相遇的节点,这个相遇的节点肯定是在环内 + +ListNode* MeetingNode(ListNode *pHead) +{ + if(pHead == nullptr) return nullptr; + + ListNode *pSlow = pHead->next; + if(pSlow == nullptr) return nullptr; + + ListNode *pFast = pSlow->next; + while(pFast != nullptr && pSlow != nullptr) + { + if(pFast == pSlow) return pFast; + + pSlow = pSlow->next; + pFast = pFast->next; + if(pFast != nullptr) { + pFast = pFast->next; + } + + } + + return nullptr; + +} + + +//在找到链表中任意一个节点后,就能得出环中的节点数目,并找到环的入口节点 + +ListNode *entryNodeOfLoop(ListNode *pHead) +{ + ListNode *meetingNode = MeetingNode(pHead); + if(meetingNode == nullptr) return nullptr; //如果不存在环就直接返回 + + //得到环中节点的数目 + int nodesInLoop = 1; + ListNode *pNode1 = meetingNode; + while(pNode1->next != nullptr) + { + pNode1 = pNode1->next; + ++nodesInLoop; + } + + //先移动pNode1,移动次数为环中节点的数目 + pNode1 = pHead; + for(int i = 0; i < nodesInLoop; i++) { + pNode1 = pNode1->next; + } + + //同时移动pNode1和pNode2 + ListNode *pNode2 = pHead; + while(pNode1 != pNode2) + { + pNode1 = pNode1->next; + pNode2 = pNode2->next; + } + + return pNode1; + +} diff --git "a/\345\211\221\346\214\207Offer/ex24.cc" "b/\345\211\221\346\214\207Offer/ex24.cc" new file mode 100755 index 0000000..71a3a1f --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex24.cc" @@ -0,0 +1,24 @@ + + +/* + 面试题24:反转链表 + 参考Leetcode第506题 +*/ + + +ListNode* reverseList(ListNode *head) +{ + ListNode *pre = nullptr; + ListNode *cur = head; + + while(cur != nullptr) + { + ListNode *pNext = cur->next; + cur->next = pre; + pre = cur; + cur = pNext; + } + + return pre; + +} diff --git "a/\345\211\221\346\214\207Offer/ex25.cc" "b/\345\211\221\346\214\207Offer/ex25.cc" new file mode 100755 index 0000000..cc84e33 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex25.cc" @@ -0,0 +1,41 @@ + + +/* + 面试题25:合并两个升序链表 +*/ + +//面试官要求讲思路的话最好画图来解释 + + + +struct ListNode{ + int value; + ListNode *next; + +}; + + +ListNode* Merge(ListNode *pHead1, ListNode *pHead2) +{ + if(pHead1 == nullptr) { + return pHead2; + } + else if(pHead2 == nullptr) { + return pHead1; + } + + ListNode *pMergeHead; + if(pHead1->value < pHead2->value) + { + pMergeHead = pHead1; + pMergeHead->next = Merge(pHead1->next, pHead2); + } + else + { + pMergeHead = pHead2; + pMergeHead->next = Merge(pHead1, pHead2->next); + } + + return pMergeHead; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex26.cc" "b/\345\211\221\346\214\207Offer/ex26.cc" new file mode 100755 index 0000000..7d54fc3 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex26.cc" @@ -0,0 +1,72 @@ + + +/* + 面试题26:树的子结构 + 输入两颗二叉树A和B,判断B是否是A的子树 +*/ + +//思路 +//1.在树A中找到树B的根节点一样的节点R +//2.判断在树A中以R为节点的子树是不是包含和树B一样的结构 + + +struct binaryTreeNode { + double val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +bool hasSubtree(binaryTreeNode *pRoot1, binaryTreeNode *pRoot2) +{ + bool result = false; + + if(pRoot1 != nullptr && pRoot2 != nullptr) + { + //在树A中找到了树B的根节点,接下来判断树A是否包含树B + if(equal(pRoot1->val, pRoot2->val)){ + result = doesTree1HaveTree2(pRoot1, pRoot2); + } + + //没有找到树B的根节点,往树A的左子树搜索 + if(!result){ + result = hasSubtree(pRoot1->left, pRoot2); + } + + //没有找到树B的根节点,往树A的右子树搜索 + if(!result){ + result = hasSubtree(pRoot1->right, pRoot2); + } + + } + + return result; + +} + + +bool doesTree1HaveTree2(binaryTreeNode *pRoot1, binaryTreeNode *pRoot2) +{ + //一直搜索到了树B的叶节点,则说明成功;这两个if语句不能调换顺序 + if(pRoot2 == nullptr) return true; + + //搜索到了树A的叶节点,则说明失败 + if(pRoot1 == nullptr) return false; + + if(!equal(pRoot1->val, pRoot2->val)) return false; + + return doesTree1HaveTree2(pRoot1->left, pRoot2->left) && doesTree1HaveTree2(pRoot1->right, pRoot2->right); + +} + + +//判断两个浮点数是否相等 +bool equal(double num1, double num2) +{ + if(num1-num2 > -0.00000001 && num1-num2 < 0.00000001){ + return true; + } + + return false; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex27.cc" "b/\345\211\221\346\214\207Offer/ex27.cc" new file mode 100755 index 0000000..ea5fb52 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex27.cc" @@ -0,0 +1,43 @@ + + +/* + 面试题27:二叉树的镜像 (Leetcode第226题) + 输入一颗二叉树,完成它的镜像输出 +*/ + +//思路: +//1.先前序遍历二叉树的节点,如果遍历到的节点有子节点,则交换它的两个子节点 +//2.当交换完所有的非叶节点的左右节点之后,就得到了数的镜像 + + +struct binaryTreeNode{ + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +void mirrorRecursively(binaryTreeNode *pNode) +{ + if(pNode == nullptr) return; + + //遍历到了叶子节点 + if(pNode->left == nullptr && p->right == nullptr) return; + + //将左右节点交换 + binaryTreeNode *tmp = pNode->left; + binaryTreeNode pNode->left = pNode->right; + binaryTreeNode pNode->right = tmp; + + //遍历左子树 + if(pNode->left != nullptr){ + mirrorRecursively(pNode->left); + } + + //遍历右子树 + if(pNode->right != nullptr){ + mirrorRecursively(pNode->right); + } + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex28.cc" "b/\345\211\221\346\214\207Offer/ex28.cc" new file mode 100755 index 0000000..04461cc --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex28.cc" @@ -0,0 +1,39 @@ + + +/* + 面试题28:对称的二叉树 + 判断一颗二叉树是否和它的镜像相同 +*/ + + +//思路:二叉树的镜像是将左右子节点交换得来的 +//也就是说如果我们先遍历二叉树的右子节点再遍历左子节点,如果得到的序列和前序遍历的序列一样就说明这颗二叉树是对称的; +//反之有一个节点不一样则不是对称的 +//需要注意的是nullptr指针也要考虑进去 + + +struct binaryTreeNode{ + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +bool isSymmetric(binaryTreeNode *pRoot) +{ + return isSymmetricCore(pRoot, pRoot); + +} + +bool isSymmetricCore(binaryTreeNode *pRoot1, binaryTreeNode *pRoot2) +{ + if(pRoot1 == nullptr && pRoot2 == nullptr) return true; + + if(pRoot1 == nullptr || pRoot2 == nullptr) return false; + + if(pRoot1->val != pRoot2->val) return false; + + return isSymmetricCore(pRoot1->left, pRoot2->right) && isSymmetricCore(pRoot1->right, pRoot2->left); + +} diff --git "a/\345\211\221\346\214\207Offer/ex29.cc" "b/\345\211\221\346\214\207Offer/ex29.cc" new file mode 100755 index 0000000..7ef0517 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex29.cc" @@ -0,0 +1,81 @@ +//面试题29:顺时针打印矩阵元素 + + +//找规律 + +#include + +void PrintMatrixClockwisely(int **number, int row, int col); +void PrintMatrixInCircle(int **number, int row, int col, int start); +void printNumber(int num); + + +int main(){ + int number[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; + int *p[4]; + p[0] = number[0]; + p[1] = number[1]; + p[2] = number[2]; + p[3] = number[3]; + + + PrintMatrixClockwisely(p, 4, 4); + std::cout << std::endl; + + + return 0; +} + + +void PrintMatrixClockwisely(int **number, int row, int col) +{ + if(number==nullptr && row<=0 && col<=0) return; + + int start = 0; + while(col>start*2 && row>start*2){ + PrintMatrixInCircle(number, row, col, start); + start++; + } + +} + +void PrintMatrixInCircle(int **number, int row, int col, int start){ + int endX = row-1-start; + int endY = col-1-start; + + //从左到右打印第一行 + for(int i = start; i <= endY; i++){ + int num = number[start][i]; + printNumber(num); + } + + //从上到下打印第一列 + if(start < endX){ + for(int i = start+1; i <= endX; i++){ + int num = number[i][endY]; + printNumber(num); + } + } + + //从右到左打印第二行 + if(start < endX && start < endY){ + for(int i = endY-1; i >= start; i--){ + int num = number[endX][i]; + printNumber(num); + } + } + + //从下到上打印第二列 + if(start < endX-1 && start < endY){ + for(int i = endX-1; i >= start+1; i--){ + int num = number[i][start]; + printNumber(num); + } + } + +} + + +void printNumber(int num){ + std::cout << num << " "; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex3.cc" "b/\345\211\221\346\214\207Offer/ex3.cc" new file mode 100755 index 0000000..3a063a2 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex3.cc" @@ -0,0 +1,130 @@ + + +/* + 面试题3:数组中重复的数字(Leetcode第287题) + + 1.找出数组中重复的数字 + + 2.不修改数组找出重复的数字 +*/ + + +#include + +bool duplicate(int numbers[], int length, int *duplication); +int getDuplication(const int *numbers, int length); +int countRange(const int *numbers, int length, int start, int end); + + +int main() { + int num[] = {1,2,3,3}; + int n = sizeof(num)/sizeof(num[0]); + // int duplication = -1; + + // if(duplicate(num, n, &duplication)) { + // std::cout << duplication << std::endl; + // } + + std::cout << getDuplication(num, n) << std::endl; + + + return 0; +} + + + +//1.找出数组中重复的数字 + +bool duplicate(int numbers[], int length, int *duplication) +{ + if(numbers == nullptr || length <= 0) return false; + + //不满足每个数都小于数组长度的条件,直接返回 + for(int i = 0; i < length; i++) + { + if(numbers[i] < 0 || numbers[i] > length-1) { + return false; + } + } + + for(int i = 0; i < length; i++) + { + while(numbers[i] != i) + { + if(numbers[i] == numbers[numbers[i]]) { + *duplication = numbers[i]; + return true; + } + + std::swap(numbers[i], numbers[numbers[i]]); + } + + } + + return false; + +} + + + + +//2.不修改数组找出重复的数字 +//利用二分法(时间复杂度为O(nlogn), 空间复杂度为O(1)) + +int getDuplication(const int *numbers, int length) +{ + //空数组或者数组只有一个元素,直接返回-1 + if(numbers == nullptr || length <= 1) return -1; + + //不满足每个元素都小于数组长度 + for(int i = 0; i < length; i++) + { + if(numbers[i] < 0 || numbers[i] >= length) { + return -1; + } + } + + + int start = 1; + int end = length-1; + + while(end >= start) + { + int middle = ((end-start)>>1) + start; + int count = countRange(numbers, length, start, middle); + + if(end == start) + { + if(count > 1) return start; + else break; + } + + if(count > (middle-start+1)) { + end = middle - 1; + } + else { + start = middle + 1; + } + + } + + return -1; + +} + + +int countRange(const int *numbers, int length, int start, int end) +{ + if(numbers == nullptr) return 0; + + int count = 0; + for(int i = 0; i < length; i++) + { + if(numbers[i] >= start && numbers[i] <= end) { + ++count; + } + } + + return count; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex30.cc" "b/\345\211\221\346\214\207Offer/ex30.cc" new file mode 100755 index 0000000..abd0124 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex30.cc" @@ -0,0 +1,109 @@ +//面试题30 + +/* + 包含min函数的栈(min函数是取栈中元素的最小值) +*/ + +//思路: +//题目要求是定义一个特殊的栈,这个栈的min,push,pop函数的时间复杂度都是O(1) +//不要以为将栈中元素重新排序后得到最小值就可以了,这样栈的数据结构就被破坏了, +//顺序全都打乱了,最先入栈的元素不一定最先弹出 + +//定义一个辅助栈,比如现在压入栈的元素是3421; +//数据栈压入元素3,辅助栈初始为空,压入元素3 +//数据栈压入元素4,由于辅助栈的栈顶元素小于4,故接着压入3; 数据栈为3,4; 辅助栈为3,3 +//数据栈压入元素2,由于辅助栈的栈顶元素大于2,此时压入2 数据栈为3,4,2; 辅助栈为3,3,2 +//数据栈压入元素1,由于辅助栈的栈顶元素大于1,此时压入1 数据栈为3,4,2,1; 辅助栈为3,3,2,1 + +//这样无论数据栈是压入元素还是弹出元素,辅助栈栈顶元素都是当前数据栈中元素的最小值 + + +//这种写法没有使用assert函数,下面的第二种写法使用了assert函数 +template void StackWithMin::push(const T &value){ + m_data.push(value); + + if(m_min.size()==0 || value void StackWithMin::pop(){ + if(m_data.size>0 && m_min.size()>0){ + m_data.pop(); + m_min.pop(); + }else{ + std::cout << "Error" << std::endl; + exit(0); + } + +} + + +template const T& StackWithMin::min() const{ + if(m_data.size>0 && m_min.size()>0){ + return m_min.top(); + } + +} + + + +//测试算例 +#include +#include +#include + + +template class StackWithMin{ + public: + StackWithMin() {} + virtual ~StackWithMin() {} + + T& top(); + const T& top() const; + + void push(const T& value); //主要实现这三个关键函数即可 + void pop(); + const T& min() const; + + bool empty() const; + size_t size() const; + + private: + std::stack m_data; //定义两个栈,一个存放原始数据一个存放栈中最小元素 + std::stack m_min; + +}; + + + +template void StackWithMin::push(const T& value){ + m_data.push(value); + + if(m_min.size()==0 || value void StackWithMin::pop(){ + assert(m_data.size()>0 && m_min.size()>0); + + m_data.pop(); + m_min.pop(); + +} + +template const T& StackWithMin::min() const{ + assert(m_data.size()>0 && m_min.size()>0); + + return m_min.top(); + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex31.cc" "b/\345\211\221\346\214\207Offer/ex31.cc" new file mode 100755 index 0000000..648438d --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex31.cc" @@ -0,0 +1,53 @@ + + +/* + 面试题题31:栈的压入,弹出序列 +*/ + + +#include +#include + +bool isPopOrder(const int *pPush, const int *pPop, int nLength); + +int main(){ + int push[] = {1,2,3,4,5}; + int pop[] = {4,3,5,1,2}; + + std::cout << isPopOrder(push, pop, 5) << std::endl; + + return 0; +} + + + +bool isPopOrder(const int *pPush, const int *pPop, int nLength) +{ + if(pPush == nullptr || pPop == nullptr || nLength <= 0) return false; + + const int *pNextPush = pPush; + const int *pNextPop = pPop; + + std::stack stackData; + + while(pNextPop-pPop < nLength) + { + while(stackData.empty() || stackData.top() != *pNextPop) + { + if(pNextPush-pPush == nLength) break; + stackData.push(*pNextPush); + pNextPush++; + } + + if(stackData.top() != *pNextPop) break; + + stackData.pop(); + pNextPop++; + + } + + if(stackData.empty() && pNextPop-pPop == nLength) return true; + + return false; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex32.cc" "b/\345\211\221\346\214\207Offer/ex32.cc" new file mode 100755 index 0000000..263627f --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex32.cc" @@ -0,0 +1,167 @@ + + +/* + 面试题32:从上到下打印二叉树 : 利用队列和栈 + + 1.二叉树的层序遍历 + + 2.分行从上到下打印二叉树 + + 3.之字形打印二叉树 + +*/ + + + + +struct binaryTreeNode { + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +// 1.二叉树的层序遍历 +//思路:利用队列deque +//打印一个节点,如果该节点有子节点,则将其加入队尾,一直到所有节点被全部打印 + +void printFromTopToButton(binaryTreeNode *pTreeRoot) +{ + if(pTreeRoot == nullptr) return; + + std::deque dequeTreeNode; + + dequeTreeNode.push_back(pTreeRoot); //将根节点加入到队列中 + + while(!dequeTreeNode.size().empty()) //队列非空则继续打印 + { + //队首元素出队并打印节点的值 + binaryTreeNode *pNode = dequeTreeNode.front(); + dequeTreeNode.pop_front(); + printf("%d ", pNode->val); + + //存在子节点则先让左节点入队,再让右节点入队 + if(pNode->left != nullptr) { + dequeTreeNode.push_back(pNode->left); + } + + if(pNode->right != nullptr) { + dequeTreeNode.push_back(pNode->right); + } + + } + +} + + + + +// 2.分行从上到下打印二叉树 +//思路:还是利用队列,只不过需要额外的两个变量 +//一个用来表示当前层还没有打印的节点数;另一个变量表示下一层的节点数 + +void print(binaryTreeNode *pRoot) +{ + if(pRoot == nullptr) return; + + std::deque nodes; + + nodes.push_back(pRoot); + + //nextLevel表示下一层的节点数 + int nextLevel = 0; + + //toBePrinted保存当前层还没有打印的节点数 + int toBePrinted = 1; + + while(!nodes.empty()) + { + binaryTreeNode *pNode = nodes.front(); + nodes.pop_front(); + printf("%d ", pNode->val); + + if(pNode->left != nullptr) { + nodes.push_back(pNode->left); + ++nextLevel; + } + + if(pNode->right != nullptr) { + nodes.push_back(pNode->right); + ++nextLevel; + } + + //每打印一个节点则toBePrinted减1 + --toBePrinted; + + //toBePrinted为0表示该层节点全部打印完毕,输出换行符 + if(toBePrinted == 0) + { + printf("\n"); + toBePrinted = nextLevel; + nextLevel = 0; + } + + } + +} + + + +// 3.之字形打印二叉树 + +void print(binaryTreeNode *pRoot) +{ + if(pRoot == nullptr) return; + + //定义两个栈 + std::stack levels[2]; + + int current = 0; + int next = 1; + + levels[current].push(pRoot); + while(!levels[0].empty() || !levels[1].empty()) + { + binaryTreeNode *pNode = levels[current].top(); + levels[current].pop(); + printf("%d ", pNode->val); + + //规定栈level[0]中的的元素节点子节点入栈level[1] + //对栈levels[1],但是要求左子节点先入栈,右子节点后入栈 + if(current == 0) + { + if(pNode->left != nullptr) { + levels[next].push(pNode->left); + } + + if(pNode->right != nullptr) { + levels[next].push(pNode->right); + } + + } + + //同样规定栈levels[1]中的元素入栈levels[0] + //对栈levels[0],要求右子节点先入栈,左子节点后入栈 + else + { + if(pNode->right != nullptr) { + levels[next].push(pNode->right); + } + + if(pNode->levels != nullptr) { + levels[next].push(pNode->left); + } + + } + + //当前栈中元素全部打印完毕,则输出换行符,交换栈继续打印下一层 + if(levels[current].empty()) + { + printf("\n"); + current = 1-current; + next = 1-next; + } + } + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex33.cc" "b/\345\211\221\346\214\207Offer/ex33.cc" new file mode 100755 index 0000000..eff7ab8 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex33.cc" @@ -0,0 +1,46 @@ + + +/* + 面试题33:二叉搜索树的后序遍历 + 给出一个整数数组,判断该数组是否为二叉搜索树的后序遍历结果 +*/ + + +bool verifySequenceOfBST(int sequence[], int length) +{ + if(sequence == nullptr || length <= 0) return false; + + //根节点的值 + int root = sequence[length-1]; + + //二叉搜索树中左子树的节点值小于根节点的值 + int i = 0; + for(; i < length-1; i++) + { + if(sequence[i] > root) break; + } + + //二叉搜索树的右子树的节点值都大于根节点的值 + int j = i; + for(; j < length-1; j++) + { + if(sequence[j] < root) return false; + } + + //判断左子树是不是二叉搜索树 + bool left = true; + if(i > 0) { + left = verifySequenceOfBST(sequence, i); + } + + //判断右子树是不是二叉搜索树 + bool right = true; + if(i < length-1) { + right = verifySequenceOfBST(sequence + i, length-1-i); + } + + return (left && right); + +} + + diff --git "a/\345\211\221\346\214\207Offer/ex34.cc" "b/\345\211\221\346\214\207Offer/ex34.cc" new file mode 100755 index 0000000..760960d --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex34.cc" @@ -0,0 +1,59 @@ + + +/* + 面试题34:二叉树和为某一值的路径 + 打印二叉树中节点值的和为输入整数的所有路径;从树的根节点开始往下一直到叶节点所经过的节点形成一条路径 +*/ + + +struct binaryTreeNode{ + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +void findPath(binaryTreeNode *root, int expectedSum) +{ + if(root == nullptr) return; + + std::vector path; + int currentSum = 0; + + findPathCore() + +}; + +void findPathCore(binaryTreeNode *root, int expectedSum, std::vector &path, int currentSum) +{ + //将当前遍历的节点加入到路径中 + currentSum += root->val; + path.push_back(root->val); + + //如果是叶节点,并且这条路径上节点值的和等于输入的值 + //那么就打印这条路径 + bool isLeaf = (root->left == nullptr) && (root->right == nullptr); + if(currentSum == expectedSum && isLeaf) + { + std::cout << "A path is founded: "; + for(auto num : path) { + std::cout << num << " "; + } + std::cout << std::endl; + + } + + //如果不是叶节点,则遍历它的子节点 + if(root->left != nullptr) { + findPathCore(root->left, expectedSum, path, currentSum); + } + + if(root->right != nullptr) { + findPathCore(root->right, expectedSum, path, currentSum); + } + + //返回父节点之前,在路径上删除当前节点 + path.pop_back(); + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex35.cc" "b/\345\211\221\346\214\207Offer/ex35.cc" new file mode 100755 index 0000000..15d66c5 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex35.cc" @@ -0,0 +1,167 @@ +/* + 面试题35:复杂链表的复制 +*/ + +//方法一:利用哈希表 + +//方法二: + +struct ComplexListNode { + int m_nVal; + ComplexListNode *m_pNext; + ComplexListNode *m_pSibling; +}; + + +//第一步: +//复制原始链表的任意节点N并创建新的节点N' + +void cloneNodes(ComplexListNode *pHead) +{ + ComplexListNode *pNode = pHead; + while(pNode != nullptr) + { + ComplexListNode *pCloned = new ComplexListNode(); + pCloned->m_nVal = pNode->m_nVal; + pCloned->m_pNext = pNode->m_pNext; + pCloned->m_pSibling = nullptr; + + pNode->m_pNext = pCloned; + pNode = pCloned->m_pNext; + + } + +} + +//第二步: +//如果原始链表上的节点N的m_pSilbing指向s,则它对应的复制节点N'的m_pSibling指向S的复制节点S' + +void connectSiblingNodes(ComplexListNode *pHead) +{ + ComplexListNode *pNode = pHead; + + while(pNode != nullptr) + { + ComplexListNode *pCloned = pNode->m_pNext; + if(pNode->m_pSibling != nullptr) { + pCloned->m_pSibling = pNode->m_pSibling->m_pNext; + } + + pNode = pCloned->m_pNext; + } + +} + + +//第三步: +//把第二步得到的长链表拆分成两个链表 + +ComplexListNode* reconnectNodes(ComplexListNode *pHead) +{ + ComplexListNode *pNode = pHead; + ComplexListNode *pClonedHead = nullptr; + ComplexListNode *pClonedNode = nullptr; + + if(pNode != nullptr) + { + pClonedHead = pClonedNode = pNode->m_pNext; + pNode->m_pNext = pClonedNode->m_pNext; + pNode = pNode->m_pNext; + } + + while(pNode != nullptr) + { + pClonedNode->m_pNext = pNode->m_pNext; + pClonedNode = pClonedNode->m_pNext; + pNode->m_pNext = pClonedNode->m_pNext; + pNode = pNode->m_pNext; + } + + return pClonedHead; + +} + + + +//把上面三步合并起来 + +ComplexListNode* clone(ComplexListNode *pHead) +{ + cloneNodes(pHead); + connectSiblingNodes(pHead); + + return reconnectNodes(pHead); + +} + + + +//Leetcode第138题 + +//O(n)时间,O(n)空间 +Node* copyRandomList(Node *head) +{ + if(head == nullptr) return head; + + Node *cur = head; + std::unordered_map hash; + while(cur) + { + Node *copy = new Node(cur->val); + hash[cur] = copy; + cur = cur->next; + } + + cur = head; + while(cur) + { + hash[cur]->next = hash[cur->next]; + hash[cur]->random = hash[cur->random]; + cur = cur->next; + } + + return hash[head]; +} + +//不使用哈希表 +Node* copyRandomList(Node *head) +{ + if(head == nullptr) return head; + + //复制每个链表 + Node *cur = head; + while(cur) + { + Node *pNext = cur->next; + cur->next = new Node(cur->val); + cur->next->next = pNext; + cur = pNext; + } + + //复制随机指针 + cur = head; + while(cur) + { + if(cur->random != nullptr) { + cur->next->random = cur->random->next; + } + cur = cur->next->next; + } + + //提取出偶数编号的节点 + cur = head; + Node *copyHead = head->next; + Node *copy = copyHead; + + while(copy->next) { + cur->next = cur->next->next; + cur = cur->next; + + copy->next = copy->next->next; + copy = copy->next; + } + + cur->next = nullptr; + + return copyHead; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex36.cc" "b/\345\211\221\346\214\207Offer/ex36.cc" new file mode 100755 index 0000000..864fd30 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex36.cc" @@ -0,0 +1,52 @@ + + +/* + 面试题36:二叉搜索树转换成双向链表 +*/ + +struct binaryTreeNode{ + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + +binaryTreeNode* convert(binaryTreeNode *pRootOfTree) +{ + binaryTreeNode *pLastNodeInList = nullptr; + convertNode(pRootOfTree, &pLastNodeInList); + + //pLastNodeInList指向的是双向链表的尾节点 + //我们需要返回头结点 + binaryTreeNode *pHeadOfList = pLastNodeInList; + while(pHeadOfList != nullptr && pHeadOfList->left != nullptr) { + pHeadOfList = pHeadOfList->left; + } + + return pHeadOfList; + +} + + +void convertNode(binaryTreeNode *pNode, binaryTreeNode **pLastNodeInList) +{ + if(pNode == nullptr) return; + + binaryTreeNode *pCurrent = pNode; + if(pCurrent->left != nullptr) { + convertNode(pCurrent->left, pLastNodeInList); + } + + pCurrent->left = *pLastNodeInList; + if(*pLastNodeInList != nullptr) { + (*pLastNodeInList)->right = pCurrent; + } + + *pLastNodeInList = pCurrent; + + if(pCurrent->right != nullptr) { + convertNode(pCurrent->right, pLastNodeInList); + } + +} + diff --git "a/\345\211\221\346\214\207Offer/ex37.cc" "b/\345\211\221\346\214\207Offer/ex37.cc" new file mode 100755 index 0000000..0415108 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex37.cc" @@ -0,0 +1,37 @@ + + +/* + 面试题37:序列化二叉树 +*/ + + +void serialize(BinaryTreeNode *pRoot, ostream &stream) +{ + if(pRoot == nullptr) { + stream << "$,"; + return; + } + + stream << pRoot->value << ','; + serialize(pRoot->left, stream); + serialize(pRoot->right, stream); + +} + + +void deserialize(BinaryTreeNode **pRoot, istream &stream) +{ + int number; + + if(ReadStream(stream, &number) //ReadStream函数每次从流中读入一个数字或者字符"$",当从流中读入一个数字时,返回true,否则返回false + { + *pRoot = new BinaryTreeNode(); + (*pRoot)->value = number; + (*pRoot)->left = nullptr; + (*pRoot)->right = nullptr; + + deserialize(&((*pRoot)->left), stream); + deserialize(&((*pRoot)->right), stream); + } + +} diff --git "a/\345\211\221\346\214\207Offer/ex38.cc" "b/\345\211\221\346\214\207Offer/ex38.cc" new file mode 100755 index 0000000..338c0d9 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex38.cc" @@ -0,0 +1,85 @@ + + +/* + 面试题38:字符串的全排列 +*/ + +#include + +void permutationCore(char *pStr, char *pBegin) +{ + if(*pBegin == '\0') + { + std::cout << pStr << std::endl; + } + else + { + for(char *pCh = pBegin; *pCh != '\0'; pCh++) + { + char tmp = *pCh; + *pCh = *pBegin; + *pBegin = tmp; + + permutationCore(pStr, pBegin + 1); + + //之前交换完毕的要复原回来方便第二个字母做首字母的全排列 + tmp = *pCh; + *pCh = *pBegin; + *pBegin = tmp; + } + + } + +} + +void permutation(char *pStr) +{ + if(pStr == nullptr) return; + + permutationCore(pStr, pStr); + +} + +int main(){ + char str[] = ""; + + permutation(str); + + return 0; +} + + + + +//C++写法,利用string + +void permutation(std::string &str) +{ + if(str.empty()) return ; + + permutationCore(str, 0); + + +} + +void permutationCore(std::string &str, int pos) +{ + if(pos == str.size()) { + std::cout << str << std::endl; + } + + for(int i = pos; i < str.size(); i++) + { + char temp = str[pos]; + str[pos] = str[i]; + str[i] = temp; + + permutationCore(str, pos+1); + + temp = str[pos]; + str[pos] = str[i]; + str[i] = temp; + } + +} + diff --git "a/\345\211\221\346\214\207Offer/ex39.cc" "b/\345\211\221\346\214\207Offer/ex39.cc" new file mode 100755 index 0000000..83aad55 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex39.cc" @@ -0,0 +1,114 @@ + + +//面试题39 : 数组中出现次数超过数组长度一半的数 +//两种解法 + + + +int partition(int num[], int len, int low, int hig) { + if(num == nullptr || len <= 0 || low < 0 || hig >= len){ + std::cout << "Error"; + exit(1); + } + + int pivotkey = num[low]; + while(low < hig) + { + while(low < hig && num[hig] >= pivotkey){ + hig--; + } + num[low] = num[hig]; + + while(low < hig && num[low] <= pivotkey){ + low++; + } + num[hig] = num[low]; + } + + num[low] = pivotkey; + + return low; +} + + +bool checkMoreThanHalf(int number[], int length, int target) { + int times = 0; + for(int i = 0; i < length; i++){ + if(number[i] == target) times++; + } + + bool isMoreThanHalf = true; + + if(times*2 <= length){ + isMoreThanHalf = false; + } + + return isMoreThanHalf; +} + + + + +//解法一:利用快排的思想 +//注:这种解法会修改输入的数组,即因为会交换数组中元素的顺序,这就会修改输入的数组 + +int moreThanHalfNum(int *number, int length) +{ + if(number == nullptr || length <= 0) return 0; //检测输入参数是否合法 + + int middle = length/2; + int start = 0; + int end = length-1; + int index = partition(number, length, start, end); + + while(index != middle){ + if(index > middle){ + end = index-1; + index = partition(number, length, start, end); + } + + if(index < middle){ + start = index+1; + index = partition(number, length, start, end); + } + + } + + int result = number[middle]; + + if(!checkMoreThanHalf(number, length, result)){ //检查数组中位数出现的次数是否大于数组长度的一半 + result = 0; + } + + return result; +} + + + + + + +//解法二:(推荐使用这种解法) +//利用数组本身的特点,这种解法不需要修改输入数组 + +int moreThanHalfNum(int *number, int length) +{ + if(number == nullptr || length <= 0) return 0; + + int result = number[0]; + int times = 1; + for(int i = 1; i < length; i++) { + if(times == 0) { + result = number[i]; + times = 1; + } + else if(number[i] == result) times++; + else times--; + } + + if(!checkMoreThanHalf(number, length, result)){ + result = 0; + } + + return result; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex4.cc" "b/\345\211\221\346\214\207Offer/ex4.cc" new file mode 100755 index 0000000..556d4bb --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex4.cc" @@ -0,0 +1,76 @@ +//面试题4 +//在杨氏矩阵中查找指定的数 + + +#include + +bool find(int *matrix, int rows, int colums, int number); + +int main(){ + int matrix[] = {1,2,8,9, 2,4,9,12, 4,7,10,13, 6,8,11,15}; + int rows = 4, colums = 4; + std::cout << find(matrix, rows, colums, 7) << std::endl; + + return 0; +} + + +bool find(int *matrix, int rows, int colums, int number) +{ + bool find = false; + + if(matrix != NULL || rows >= 0 || colums >= 0) + { + //从右上角开始查找 + int row = 0; + int colum = colums-1; + + while(row < rows && colums >= 0){ + if(number < matrix[row*colums+colum]) { colum--; } + + else if(number > matrix[row*colums+colum]) { row++; } + + else { find = true; break; } + } + + } + + return find; + +} + + + + + +bool Find(int *matrix, int rows, int columns, int number) +{ + bool found = false; + + if(matrix != nullptr && rows > 0 && columns > 0) + { + //从左下角开始查找 + int row = rows - 1; + int column = 0; + + while(row > 0 && column < columns) + { + if(matrix[row*columns+column] == number) { + found = true; + break; + } + + else if(matrix[row*columns+column] > number) { + row--; + } + else{ + column++; + } + } + + } + + + return found; + +} diff --git "a/\345\211\221\346\214\207Offer/ex40.cc" "b/\345\211\221\346\214\207Offer/ex40.cc" new file mode 100755 index 0000000..9c50551 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex40.cc" @@ -0,0 +1,99 @@ + + +//面试题40 : 最小的k个数 + + + +//方法一: +//这种方法会修改输入的数组 + +void getLeastNumber(int *input, int n, int *output, int k) +{ + if(input == nullptr || output == nullptr || k > n || n <= 0 || k <= 0) return; + + int start = 0; + int end = n-1; + int index = partition(input, n, start, end); + + while(index != k-1){ + if(index > k-1){ + end = index -1; + index = partition(input, n, start, end); + + }else{ + start = index + 1; + index = partition(input, n, start, end); + + } + } + + for(int i = 0; i < k; i++){ + output[i] = input[i]; + } + +} + + +//方法二: +//该方法不会修改输入的数组 + +//greater函数在头文件 +//set和multiset都是在中,multiset中允许出现重复元素 + +typedef std::multiset> intSet; //用来构建一个最大堆 +typedef std::multiset> ::iterator setIterator; + +void getLeastNumbers(const std::vector &data, intSet &leastNumbers, int k) +{ + leastNumbers.clear(); + + if(k < 1 || data.size() < k) return; + + std::vector::const_iterator iter = data.begin(); + for(; iter != data.end(); iter++) + { + if(leastNumbers.size() < k) { + leastNumbers.insert(*iter); + } + else { + setIterator iterGreatest = leastNumbers.begin(); + if(*iter < *(leastNumbers.begin())) { + leastNumbers.erase(iterGreatest); + leastNumbers.insert(*iter); + } + } + } + +} + + + +//附:如何求最大的k个数 +//最大的k个数 +void getLeastNumber_1(int *input, int n, int *output, int k) +{ + if(input == nullptr || output == nullptr || k > n || n <= 0 || k <= 0) return; + + int start = 0; + int end = n-1; + int index = partition(input, n, start, end); + + while(index != (n-k)){ + if(index > n-k){ + end = index -1; + index = partition(input, n, start, end); + + }else{ + start = index + 1; + index = partition(input, n, start, end); + + } + } + + for(int i = 0; i < k; i++){ + output[i] = input[index++]; + } + +} + + diff --git "a/\345\211\221\346\214\207Offer/ex41.cc" "b/\345\211\221\346\214\207Offer/ex41.cc" new file mode 100755 index 0000000..f7365d7 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex41.cc" @@ -0,0 +1,40 @@ + + +//面试题41:数据流中的中位数 +//参看Leetcode第295题(利用优先队列) + + +class MedianFinder +{ +public: + MedianFinder() {} + + void addNum(int num) { + if(maxQue.empty() || num < maxQue.top()) maxQue.push(num); + else minQue.push(num); + + if(maxQue.size() > (minQue.size() + 1)) { + minQue.push(maxQue.top()); + maxQue.pop(); + } + else if((maxQue.size() + 1) < minQue.size()) { + maxQue.push(minQue.top()); + minQue.pop(); + } + } + + double findMedian() { + if(maxQue.size() == minQue.size()) { + return maxQue.empty() ? 0 : (maxQue.top() + minQue.top()) / 2.0; + } + else { + return (maxQue.size() > minQue.size()) ? maxQue.top() : minQue.top(); + } + } + + +private: + std::priority_queue maxQue; + std::priority_queue, std::greater> minQue; + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex42.cc" "b/\345\211\221\346\214\207Offer/ex42.cc" new file mode 100755 index 0000000..e5db091 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex42.cc" @@ -0,0 +1,71 @@ + + +/* + 面试题42:连续子数组的最大和 + 同Leetcode第53题 +*/ + +//思路:动态规划 + + +#include + +int findGreatSumOfSubarray(int *pData, int length); + +int main(){ + int data[] = {1,-2,3,10,-4,7,2,-5}; + int n = sizeof(data)/sizeof(data[0]); + + std::cout << findGreatSumOfSubarray(data, n) << std::endl; + + return 0; +} + +int findGreatSumOfSubarray(int *pData, int length) +{ + if(pData == nullptr || length <= 0) { + return -1; + } + + int dp[length]; + dp[0] = pData[0]; + + int res = dp[0]; + + for(int i = 1; i < length; i++) + { + if(dp[i-1] < 0) { + dp[i] = pData[i]; + } + else { + dp[i] = dp[i-1] + pData[i]; + } + + res = std::max(res, dp[i]); + } + + return res; +} + + + +//Leetcode第53题,可看成是对上面动态规划的优化,不需要一个数组来存储每个值 +//时间复杂度O(n), 空间复杂度O(1) + +int findGreatSumOfSubarray(std::vector &nums) +{ + int res = INT_MIN; + int sum = 0; + + for(int n:num) + { + sum += n; + if(n > sum) { + sum = n; + } + + res = std::max(res, sum); + } + + return sum; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex43.cc" "b/\345\211\221\346\214\207Offer/ex43.cc" new file mode 100755 index 0000000..37e5280 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex43.cc" @@ -0,0 +1,156 @@ + + + +/* + 面试题43:1~n整数中1出现的次数 +*/ + +#include +#include + +int numberOf1Between1AndN(unsigned int n); +int numberOf1(unsigned int n); + +int numberOf1Between1AndN(int n); +int numberOf1(const char* strN); +int powerBase10(unsigned int n); + + +int main(){ + std::cout << numberOf1Between1AndN(21345) << std::endl; + + return 0; +} + + +//方法一:暴力破解 +//时间复杂度为O(nlogn) + +int numberOf1Between1AndN(unsigned int n) +{ + int number = 0; + + for(unsigned int i = 1; i <= n; i++) { + number += numberOf1(i); + } + + return number; + +} + + +int numberOf1(unsigned int n) +{ + int number = 0; + + while(n) + { + if(n % 10 == 1) { + number++; + } + + n /= 10; + } + + return number; + +} + + + +//第二种方法,利用数字规律 +//时间复杂度为O(logn) + +int numberOf1Between1AndN(int n) +{ + if(n <= 0) return 0; + + char strN[50]; + sprintf(strN, "%d", n); //将数组转化成字符串,以防止溢出 + + return numberOf1(strN); + +} + + +int numberOf1(const char* strN) +{ + if(!strN || *strN < '0' || *strN > '9' || *strN == '\0') return 0; + + int first = *strN - '0'; //这是得到第一个字符 + unsigned int length = static_cast(strlen(strN)); + + if(length == 1 && first == 0) return 0; + if(length == 1 && first > 0) return 1; + + int numFirstDigit = 0; + if(first > 1) { + numFirstDigit = powerBase10(length-1); + } + else if(first == 1) { + numFirstDigit = atoi(strN+1)+1; + } + + int numOtherDigits = first*(length-1)*powerBase10(length-2); + + int numRecrusive = numberOf1(strN+1); + + return numFirstDigit + numOtherDigits + numRecrusive; + +} + + +int powerBase10(unsigned int n) +{ + int result = 1; + for(unsigned int i = 0; i < n; i++) { + result *= 10; + } + + return result; +} + + + + +//使用string 替代 char* + +int countDigitOne(int n) +{ + if(n <= 0) return 0; + + std::string str = std::to_string(n); + + return countDigitOneCore(str); + +} + + +int countDigitOneCore(const std::string &str) +{ + int first = str[0] - '0'; + unsigned int length = str.size(); + + if(length == 1 && first == 0) { + return 0; + } + + if(length == 1 && first > 0) { + return 1; + } + + int numFirstDigit = 0; + if(first > 1) { + numFirstDigit = (int)pow(10, length-1); + } + else if(first == 1) { + numFirstDigit = std::stoi(str.substr(1)) + 1; + } + + int numOtherDigit = first*(length-1)*(int)pow(10, length-2); + + int numRecursive = countDigitOneCore(str.substr(1)); //如果前面不加const则这里会报错 + + return numFirstDigit + numOtherDigit + numRecursive; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex44.cc" "b/\345\211\221\346\214\207Offer/ex44.cc" new file mode 100755 index 0000000..4da3595 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex44.cc" @@ -0,0 +1,75 @@ + + +/* + 面试题44:数字序列中的某一位的数字 +*/ + +#include +#include + +int digitAtIndex(int index); +int countOfIntegers(int digits); +int digitAtIndex(int index, int digits); +int beginNumber(int digits); + + +int main(){ + std::cout << digitAtIndex(1001) << std::endl; + + return 0; +} + + +int digitAtIndex(int index) +{ + if(index < 0) return -1; + + int digits = 1; + + while(true) + { + int numbers = countOfIntegers(digits); + if(index < numbers*digits) { + return digitAtIndex(index, digits); + } + + index -= digits*numbers; + digits++; + } + + return -1; + +} + + +//计算m位的数字一共有多少个 +int countOfIntegers(int digits) +{ + if(digits == 1) return 10; + + int count = (int)pow(10, digits-1); + + return 9*count; +} + + +//知道要找的那位数在位于某m位数中后,就可以用如下函数找出那一位数字 +int digitAtIndex(int index, int digits) +{ + int number = beginNumber(digits) + index/digits; + int indexFromRight = digits - index%digits; + + for(int i = 1; i < indexFromRight; i++) { + number /= 10; + } + + return number % 10; +} + + +int beginNumber(int digits) +{ + if(digits == 1) return 0; + + return (int)pow(10, digits-1); +} diff --git "a/\345\211\221\346\214\207Offer/ex45.cc" "b/\345\211\221\346\214\207Offer/ex45.cc" new file mode 100755 index 0000000..8e246f8 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex45.cc" @@ -0,0 +1,64 @@ + + + +/* + 面试题45:把数组排成最小的数 +*/ + + +//参看Leetcode第179题,书上写法太繁琐 + + +#include +#include +#include + +std::string minmunNumber(std::vector &nums); +bool cmp(std::string &s1, std::string &s2) ; + + +int main(){ + std::vector nums = {3, 32, 321}; + std::cout << minmunNumber(nums) << std::endl; + + + return 0; +} + + +bool cmp(std::string &s1, std::string &s2) +{ + return s1 + s2 < s2 + s1; +} + + +std::string minmunNumber(std::vector &nums) +{ + std::vector strNum(nums.size()); + + for(int i = 0; i < nums.size(); i++) { + strNum[i] = std::to_string(nums[i]); + } + + //排序 + sort(strNum.begin(), strNum.end(), cmp); + + //sort函数的第三个参数用来定义排序规则 + //当sort函数在类内使用时,并且定义的cmp函数也是类内成员函数时,必须在cmp函数前面加上static + //这是因为所有的普通类成员函数都不能以函数指针的形式作为其他函数的入口参数 (具体可参考Leetcode的解题写法) + + + //如果排完序后第一个字符串是0,则最后的结果一定是0 + if(strNum[0] == "0") { + return "0"; + } + + std::string res = ""; + for(int i = 0; i < strNum.size(); i++) { + res += strNum[i]; + } + + return res; + +} + diff --git "a/\345\211\221\346\214\207Offer/ex46.cc" "b/\345\211\221\346\214\207Offer/ex46.cc" new file mode 100755 index 0000000..cf5192e --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex46.cc" @@ -0,0 +1,74 @@ + + +/* + 面试题46:把数字翻译成字符串 + 从尾部往前进行搜索 +*/ + + +#include +int getTranslationCount(int number); +int getTranslationCount(const std::string &number); + + +int main(){ + std::cout << getTranslationCount(12258) << std::endl; + + return 0; +} + + +int getTranslationCount(int number) +{ + //输入的是负数就直接返回0 + if(number < 0) return 0; + + std::string numberInString = std::to_string(number); + + return getTranslationCount(numberInString); + +} + + +int getTranslationCount(const std::string &number) +{ + int length = number.size(); + int *counts = new int[length]; + int count = 0; + + for(int i = length-1; i >= 0; i--) + { + count = 0; + + if(i < length-1) { + count = counts[i+1]; + } else { + count = 1; + } + + if(i < length-1) + { + int digit1 = number[i] - '0'; + int digit2 = number[i+1] - '0'; + int converted = digit1*10 + digit2; + + if(converted >= 10 && converted <= 25) { + if(i < length-2) { + count += counts[i+2]; + } else { + count += 1; + } + } + + } + + counts[i] = count; + + } + + count = counts[0]; + delete[] counts; + + return count; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex47.cc" "b/\345\211\221\346\214\207Offer/ex47.cc" new file mode 100755 index 0000000..1451f04 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex47.cc" @@ -0,0 +1,157 @@ + + + +/* + 面试题47:礼物的最大价值 + 典型的动态规划 +*/ + + +#include +#include + +int getMaxValue_solution1(const int *values, int rows, int cols); +int getMaxValue_solution2(const int *values, int rows, int cols); + + +int main(){ + int values[] = {1,10,3,8, 12,2,9,6, 5,7,4,11, 3,7,16,5}; + + std::cout << getMaxValue_solution1(values, 4, 4) << std::endl; + std::cout << getMaxValue_solution2(values, 4, 4) << std::endl; + + return 0; +} + + + +int getMaxValue_solution1(const int *values, int rows, int cols) +{ + if(values == nullptr || rows <= 0 || cols <= 0) return 0; + + int **maxValues = new int*[rows]; + for(int i = 0; i < rows; i++) { + maxValues[i] = new int[cols]; + } + + for(int i = 0; i < rows; i++) + { + for(int j = 0; j < cols; j++) + { + int left = 0; + int up = 0; + if(i > 0) up = maxValues[i-1][j]; + if(j > 0) left = maxValues[i][j-1]; + + maxValues[i][j] = std::max(left, up) + values[i*cols+j]; + } + } + + int maxValue = maxValues[rows-1][cols-1]; + + for(int i = 0; i < rows; i++) { + delete[] maxValues[i]; + } + + delete[] maxValues; + + return maxValue; + +} + + + +//对上面解法的优化 + +int getMaxValue_solution2(const int *values, int rows, int cols) +{ + if(values == nullptr || rows <= 0 || cols <= 0) return 0; + + int *maxValues = new int[cols]; + + for(int i = 0; i < rows; i++) + { + for(int j = 0; j < cols; j++) + { + int left = 0; + int up = 0; + if(i > 0) up = maxValues[j]; + if(j > 0) left = maxValues[j-1]; + + maxValues[j] = std::max(left, up) + values[i*cols+j]; + } + } + + int maxValue = maxValues[cols-1]; + + delete[] maxValues; + + return maxValue; +} + + +//太过复杂(下面解法更好) + +//版本一:dp数组等于原来的数组维数 + +int maxValue(std::vector> &grid) +{ + int m = grid.size(), n = grid[0].size(); + std::vector> dp(m, std::vector(n, 0)); + + dp[0][0] = grid[0][0]; + + for(int j = 1; j < n; j++) { + dp[0][j] = dp[0][j-1] + grid[0][j]; + } + + for(int i = 1; i < m; i++) { + dp[i][0] = dp[i-1][0] + grid[i][0]; + } + + for(int i = 1; i < m; i++) { + for(int j = 1; j < n; j++) { + dp[i][j] = std::max(dp[i-1][j], dp[i][j-1]) + grid[i][j]; + } + } + + return dp[m-1][n-1]; +} + + +//版本二: +//从这里可以看成,如果将dp数组移动一位,则是为了更好的处理边界条件,这样更加方便 +//如果不移动dp数组,则边界条件(也就是动态规划的base更好处理),否则不是不能做,处理base case就会像上面版本一一样麻烦 + +int maxValue(std::vector> &grid) +{ + int m = grid.size(), n = grid[0].size(); + std::vector> dp(m + 1, std::vector(n + 1, 0)); + + for(int i = 1; i <= m ;i++) { + for(int j = 1; j <= n; j++) { + dp[i][j] = std::max(dp[i-1][j], dp[i][j-1]) + grid[i-1][j-1]; + } + } + + return dp[m][n]; +} + + +//版本三:压缩空间 + +int maxValue(std::vector> &grid) +{ + int m = grid.size(), n = grid[0].size(); + + std::vector dp(n + 1, 0); + + for(int i = 1; i <= m; i++) { + for(int j = 1; j <= n; j++) { + dp[j] = std::max(dp[j], dp[j-1]) + grid[i-1][j-1]; + } + } + + return dp[n]; +} + diff --git "a/\345\211\221\346\214\207Offer/ex48.cc" "b/\345\211\221\346\214\207Offer/ex48.cc" new file mode 100755 index 0000000..4861fdb --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex48.cc" @@ -0,0 +1,64 @@ + + +/* + 面试题48:最长不含重复字符的子字符串 + 动态规划 + 参考Leetcode第3题,更加简洁,使用滑动窗口 +*/ + +//注意:这种算法中不能输入空格,因为空格的ASCII码为13,小于字母a的ASCII码, +//所以下面的 position[str[i]-'a']这个下标为负数 + + +#include + +int longestSubstringWithoutDuplication(const std::string &str); + +int main(){ + + std::string str = " "; + + std::cout << longestSubstringWithoutDuplication(str) << std::endl; + + return 0; +} + +int longestSubstringWithoutDuplication(const std::string &str) +{ + int curLength = 0; + int maxLength = 0; + + int *position = new int[26]; + for(int i = 0; i < 26; i++) { + position[i] = -1; + } + + for(int i = 0; i < str.size(); i++) + { + int preIndex = position[str[i]-'a']; + + if(preIndex < 0 || i-preIndex > curLength) + { + ++curLength; + } + else + { + if(curLength > maxLength) { + maxLength = curLength; + } + + curLength = i-preIndex; + } + + position[str[i]-'a'] = i; + } + + if(curLength > maxLength) { + maxLength = curLength; + } + + delete[] position; + + return maxLength; + +} diff --git "a/\345\211\221\346\214\207Offer/ex49.cc" "b/\345\211\221\346\214\207Offer/ex49.cc" new file mode 100755 index 0000000..beea0ea --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex49.cc" @@ -0,0 +1,109 @@ + +/* + 面试题49:丑数 + 找出从小到大的第1500个数 +*/ + + + +#include + +int getUglyNumber_Solution2(int index); +int Min(int num1, int num2, int num3); + + +int main(){ + std::cout << getUglyNumber_Solution2(4) << std::endl; + + return 0; +} + +//判断一个数是否是丑数 +bool isUgly(int number) +{ + while(number%2 == 0) { + number /= 2; + } + while(number%3 == 0) { + number /= 3; + } + while(number %5 == 0) { + number /= 5; + } + +} + + +int getUglyNumber(int index) +{ + //输入的个数小于等于0,则直接返回0表示没找到 + if(index <= 0) return 0; + + int number = 0; + int uglyFound = 0; //找到了第几个丑数 + + while(uglyFound < index) + { + ++number; + if(isUgly(number)) { //判断number是否为丑数,如果为丑数将标记数加1 + ++uglyFound; //当标记的个数等于index时就代表找到了第index个丑数 + } + } + + return number; + +} + + +//方法二: +//这种方法是创建一个数组来存储丑数,按照数组中已有的丑数来生成其他的丑数 +//这就避免了上一种方法中的每次都要判定一个数是不是丑数 + +int getUglyNumber_Solution2(int index) +{ + if(index <= 0) return 0; + + int *pUglyNumber = new int[index]; + pUglyNumber[0] = 1; + int nextUglyIndex = 1; + + int *pMultiply2 = pUglyNumber; + int *pMultiply3 = pUglyNumber; + int *pMultiply5 = pUglyNumber; + + while(nextUglyIndex < index) + { + int min = Min(*pMultiply2*2, *pMultiply3*3, *pMultiply5*5); + pUglyNumber[nextUglyIndex] = min; + + while(*pMultiply2*2 <= pUglyNumber[nextUglyIndex]) { + ++pMultiply2; + } + while(*pMultiply3*3 <= pUglyNumber[nextUglyIndex]) { + ++pMultiply3; + } + while(*pMultiply5*5 <= pUglyNumber[nextUglyIndex]) { + ++pMultiply5; + } + + ++nextUglyIndex; + + } + + int ugly = pUglyNumber[index-1]; + + delete [] pUglyNumber; + + return ugly; + +} + + +int Min(int num1, int num2, int num3) +{ + int min = (num1 < num2) ? num1 : num2; + min = (min < num3) ? min : num3; + + return min; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex5.cc" "b/\345\211\221\346\214\207Offer/ex5.cc" new file mode 100755 index 0000000..0d6082c --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex5.cc" @@ -0,0 +1,147 @@ + + +/* + 面试题5:替换空格 +*/ +//这题如果用C语言有难度,但是用C++写很简单 + +//注意:需要询问面试官是在原来的字符串上进行替换还是可以创建新的字符串来进行替换 +//1.如果是在原来的字符串上进行替换,则需要保证原来的字符串后面有足够多的内存 +//2.如果可以创建新的字符串并在新的字符串上修改,那么我们可以申请足够的内存 +//但是通常面试官会要求直接在原来的字符串上进行替换,不允许申请额外内存 + + +//思路:尾插法 +//length为字符数组string的总容量,并且要比string的字符串的长度大好多 + +//C语言写法 +//时间复杂度O(n), 空间复杂度O(1) + +void replaceBlank(char string[], int length) +{ + if(string == nullptr || length <= 0) return; + + //originalLength为字符串未替换空格之前的长度 + //numberOfBlank为字符串中空格的数量 + int originalLength = 0; + int numberOfBlank = 0; + + int i = 0; + while(string[i] != '\0') + { + ++originalLength; + if(string[i] == ' ') { + ++numberOfBlank; + } + + ++i; + } + + //newLength为替换空格之后字符串的长度 + int newLength = originalLength + 2*numberOfBlank; + + //如果替换之后的字符串的长度大于原来string数组的总容量,说明替换后的新字符串原来的数组装不下 + if(newLength > length) return; + + //从尾部向前替换 + int indexOfOriginal = originalLength; + int indexOfNew = newLength; + while(indexOfOriginal >= 0 && indexOfNew > indexOfOriginal) + { + //遇到空格就开始替换 + if(string[indexOfOriginal] == ' ') + { + string[indexOfNew--] = '0'; + string[indexOfNew--] = '2'; + string[indexOfNew--] = '%'; + } + else + { + string[indexOfNew--] = string[indexOfOriginal]; + } + + --indexOfOriginal; + } + +} + +//上面方法的简化:双指针 + +void ReplaceBlank(char *str) +{ + if(str == NULL) return ; + + int n = strlen(str); + + int numBlank = 0; + for(int i = 0; i < n; i++) { + if(str[i] == ' ') numBlank++; + } + + int newLen = n + 2*numBlank; + + int i = n, j = newLen; + + while(i >= 0 && i < j) + { + if(str[i] == ' ') { + str[j--] = '0'; + str[j--] = '2'; + str[j--] = '%'; + } + else { + str[j--] = str[i]; + } + + i--; + } + +} + + +//C++写法,利用string,并且使用额外内存 +//时间复杂度O(n), 空间复杂度O(n) +std::string replaceBlank(const std::string str) +{ + std::string res; + for(auto &c:str) + { + if(c == ' ') { + res += "%20"; + } + else { + res.push_back(c); + } + } + + return res; +} + + +//C++写法,不使用额外内存 +//利用自带的find和replace函数 +void replaceBlank(std::string &str) +{ + int pos; + + while((pos = str.find(' ')) != str.npos) { + str.replace(pos, 1, "%20"); + } + +} + + + + +#include + +int main(){ + + //需要显示指定字符串的容量 + char str[20] = "We are happy."; //char str[] = "We are happy."; + replaceBlank(str, 20); //replaceBlank(str,30); 这种写法是错误的,因为不显示指定str的容量,则str的容量就只刚好容纳下现有字符串 + + std::cout << str << std::endl; + + return 0; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex50.cc" "b/\345\211\221\346\214\207Offer/ex50.cc" new file mode 100755 index 0000000..84e465f --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex50.cc" @@ -0,0 +1,315 @@ + +/* + 面试题50:第一个只出现一次的字符 +*/ + +#include +#include + +char firstNotRepeatingChar(char *pString); + +void deleteFitstFromSecond(char *pStrFirst, char *pStrSecond); +void deleteOneChar(char *str, char toBeDelete); + +int main(){ + // char str[] = "abaccdef"; + // std::cout << firstNotRepeatingChar(str) << std::endl; + + char str1[] = "We are studnet"; + char str2[] = "t"; + deleteFitstFromSecond(str1, str2); + std::cout << str1 << std::endl; + + return 0; +} + + +//题目一:在字符串中找出第一个只出现一次的字符 + +char firstNotRepeatingChar(char *pString) +{ + if(pString == nullptr) return '\0'; //'\0'是一个换行符 + + + const int tableSize = 256; + unsigned int hashTable[tableSize]; + + for(int i = 0; i < tableSize; i++){ + hashTable[i] = 0; + } + + char *pHashKey = pString; + while(*(pHashKey) != '\0'){ + hashTable[*(pHashKey++)]++; + } + + pHashKey = pString; + while(*(pHashKey) != '\0'){ + if(hashTable[*pHashKey] == 1){ + return *pHashKey; + } + pHashKey++; + } + + return '\0'; + +} + + +//题目二:字符流中第一个只出现一次的字符 + +class CharStatistics +{ +public: + CharStatistics() : index(0) { + for(int i = 0; i < 256; i++) { + occurence[i] = -1; + } + } + + void Insert(char ch) { + if(occurence[ch] == -1) { + occurence[ch] = index; + } + else if(occurence[ch] >= 0) { + occurence[ch] = -2; //存在重复的字符 + } + + index++; + } + + char FirstAppearingOnce() { + char ch = '\0'; + int minIndex = INT_MAX; + for(int i = 0; i < 256; i++) + { + if(occurence[i] >= 0 && occurence[i] < minIndex) { //这是按照字典序进行搜索的 + ch = (char)i; //但是实际字符串中字符的顺序可能不是这样,比如"ba",a先检索,但是第一个只出现一次的字符是b + minIndex = occurence[i]; + } + } + + return ch; + } + + +private: + int occurence[256]; + int index; + +}; + + + + +//相关题目一: +//解法一:时间复杂度O(n) +//在字符串1中删除在字符串2中出现过的所有字符 + +void deleteFitstFromSecond(char *pStrFirst, char *pStrSecond) +{ + if(pStrFirst == nullptr || pStrSecond == nullptr ) return ; + + int tableSize = 256; + int hashTable[tableSize] = {0}; + + char *pHashKey = pStrSecond; + while(*(pHashKey) != '\0') + { + hashTable[*(pHashKey++)]++; + } + + while(*pStrFirst != '\0') + { + if(hashTable[*pStrFirst] > 0){ + deleteOneChar(pStrFirst, *pStrFirst); + } + pStrFirst++; + } + +} + + +//删除字符串中出现的第一个指定字符(注:不是删除全部), 如str="hello", toBeDelete='l',删除结果为 "helo"; + +void deleteOneChar(char *str, char toBeDelete){ + if(str == nullptr) return; + + int len = strlen(str); + char *p = str; + for(int i = 0; str[i] != '\0' && i < len; i++) //将if改为while,则删除所有出现的指定字符,如str="hello", toBeDelete='l',删除结果为"heo" + { + if(str[i] == toBeDelete) + { + int j = i; + for(; str[j] != '\0' && j < len-1; j++) { + str[j] = str[j+1]; + } + str[j] = '\0'; + } + } + +} + + +//将上面改用C++的写法 + +void dedeleFirstFromSecond(std::string &strFirst, std::string &strSecond) +{ + std::set mySet; + for(char ch:strSecond) { + mySet.insert(ch); + } + + int len = strFirst.size(); + for(int i = 0; i < len && strFirst[i] != '\0'; i++) + { + while(mySet.find(strFirst[i]) != mySet.end()) { + strFirst.erase(i, 1); + } + } + +} + + + + +//使用C语言编写 +//时间复杂度O(n) +//哈希表 + 双指针 +void deleteFitstFromSecond(char *pFirst, char *pSecond) +{ + if(pFirst == nullptr || pSecond == nullptr) return; + + std::vector count(26, 0); + while(*pSecond != '\0') { + count[*pSecond-'a']++; + pSecond++; + } + + int cur = 0; + char *p = pFirst; + while(*p != '\0') { + if(count[*p-'a']) { + p++; + } + else { + pFirst[cur++] = *p; + p++; + } + } + + pFirst[cur] = '\0'; +} + + +//上面的C++写法 +//哈希+双指针 +void deleteFitstFromSecond(std::string &first, std::string &second) +{ + if(first.empty() || second.empty()) return; + + std::vector count(128, 0); + + for(const int &n : second) { + count[n]++; + } + + int cur = 0; + for(const int &c : first) { + if(count[c] == 0) first[cur++] = c; + } + + first = first.substr(0, cur); +} + + + + +//相关题目二: +//哈希+双指针 + +void deleteDuplicateChar(std::string &s) +{ + if(s.empty()) return; + + std::vector count(256, 0); + + int cur = 0; + for(int i = 0; i < s.size(); i++) + { + if(count[s[i]] == 0) { + s[cur++] = s[i]; + } + count[s[i]] = 1; + } + + s = s.substr(0, cur); +} + + +//相关题目三: + +bool isAnagrams(const std::string &s, const std::string &t) +{ + if(s.size() != t.size()) return false; + + std::vector count(26, 0); + + for(int i = 0; i < s.size(); i++) + { + count[s[i]-'a']++; + count[t[i]-'a']--; + } + + for(int i = 0; i < 26; i++) { + if(count[i]) return false; + } + + return true; +} + + +//字符流中第一个只出现一次的数字 + +class CharStatistics +{ +private: + int index; + std::vector count; + +public: + CharStatistics() : index(0) { + count = std::vector(256, -1); + } + + void insert(char ch) + { + if(count[ch] == -1) { //代表该字符没有出现过 + count[ch] = index; //将其在count数组中的值置为下标 + } + else if(count[ch] >= 0) { + count[ch] = -2; //已经出现过将其置为-2,以后不用再管了 + } + + index++; + } + + char firstAppearingOnce() + { + int minIndex = index; + + char ch = '\0'; + + for(int i = 0; i < 256; i++) + { + if(count[i] >= 0 && minIndex > count[i]) { + minIndex = count[i]; + ch = (char)i; + } + } + + return ch; + } + +}; diff --git "a/\345\211\221\346\214\207Offer/ex51.cc" "b/\345\211\221\346\214\207Offer/ex51.cc" new file mode 100755 index 0000000..a8f4a9e --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex51.cc" @@ -0,0 +1,160 @@ +//面试题51 +//数组中的逆序对 + +//思路:归并排序的思想 + + +#include + +int inversePairs(int *data, int len); +int inversePairsCore(int *data, int *copy, int start, int end); + +int main(){ + int data[4] = {7,5,6,4}; + std::cout << inversePairs(data,4) << std::endl; + + return 0; +} + + +int inversePairs(int *data, int len) +{ + if(data == nullptr || len < 0) return 0; + + int *copy = new int[len]; + for(int i = 0; i < len; i++) { + copy[i] = data[i]; //这个copy数组必须要和data数组元素相同 + } + + int count = inversePairsCore(data, copy, 0, len-1); + + delete[] copy; + + return count; + +} + +int inversePairsCore(int *data, int *copy, int start, int end) +{ + if(start == end) { + copy[start] = copy[end]; + return 0; //递归的出口不要忘记了 + } + + int length = (end-start)/2; + + int left = inversePairsCore(copy, data, start, start+length); //弄清楚这个copy和data的顺序,更改的是第二个参数数组data的值 + int right = inversePairsCore(copy, data, start+length+1, end); //下面的操作都是在对copy数组操作,所以这里递归调用的第二个参数应该是data数组 + + int i = start+length; //i初始化为前半段最后一个数字的下标 + int j = end; //j初始化为后半段最后一个数字的下标 + int indexCopy = end; //这是将data中的数据从后往前复制到copy数组中 + int count = 0; + + while(i >= start && j >= start+length+1) + { + if(data[i] > data[j]) + { + copy[indexCopy--] = data[i--]; + count += j - (start + length); //(start+length)是前半段最后一个元素的下标 + } + else + { + copy[indexCopy--] = data[j--]; + } + + } + + for(; i >= start; i--) { + copy[indexCopy--] = data[i]; + } + + for(; j >= start+length+1; j--) { + copy[indexCopy--] = data[j]; + } + + return left + right + count; + +} + + +//Leetcode第493题 +//下面这种归并比较好理解 + +int inversePairs(std::vector &nums, int left, int right) +{ + if(left == right) { + return 0; + } + + int mid = left + ((right - left) >> 1); + int leftCount = inversePairs(nums, left, mid); + int rightCount = inversePairs(nums, mid + 1, right); + + //在归并的过程中加入了计算逆序的过程 +/* + int count = 0; + int i = mid, j = right; + while(i >= left && j >= mid + 1) + { + if(nums[i] > 2*nums[j]) { + count += (right - mid); + i--; + } + else { + j--; + } + } +*/ + + //注:写成上面那种形式是错误的 + int i = left, j = mid + 1 ; + while(i <= mid && j <= right) + { + if(nums[i] > 2*nums[j]) { + count += (mid - i + 1); + j++; + } + else { + i++; + } + } + + //有序合并子数组 + merge(nums, left, mid, right); + + return count + leftCount + rightCount; +} + + +void merge(std::vector &nums, int left, int mid, int right) +{ + int *team = new int[right - left + 1]; + int index = 0; + int lindex = left, rindex = mid + 1; + while(lindex <= mid && rindex <= right) + { + if(nums[lindex] <= nums[rindex]) { + team[index++] = nums[lindex++]; + } + else { + team[index++] = nums[rindex++]; + } + } + + while(lindex <= mid) { + team[index++] = nums[lindex++]; + } + + while(rindex <= right) { + team[index++] = nums[rindex++]; + } + + for(int i = 0; i < index; i++) { + nums[left + i] = team[i]; + } + + delete [] team; +} + + diff --git "a/\345\211\221\346\214\207Offer/ex52.cc" "b/\345\211\221\346\214\207Offer/ex52.cc" new file mode 100755 index 0000000..5d64ea5 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex52.cc" @@ -0,0 +1,62 @@ + + +/* + 面试题52:两个链表的第一个公共节点 +*/ + +struct ListNode{ + int key; + ListNode *next; + +}; + + +ListNode* findFirstCommonNode(ListNode *pHead1, ListNode *pHead2) +{ + //得到两个链表的长度 + unsigned int nLength1 = getListLength(pHead1); + unsigned int nLength2 = getListLength(pHead2); + int nLengthDif = nLength1 - nLength2; + + ListNode *pListHeadLong = pHead1; + ListNode *pListHeadShort = pHead2; + if(nLength2 > nLength1) + { + pListHeadLong = pHead2; + pListHeadShort = pHead1; + nLengthDif = nLength2 - nLength1; + } + + //现在长链表上走几步,再同时在两个链表上遍历 + for(int i = 0; i < nLengthDif; i++) { + pListHeadLong = pListHeadLong->next; + } + + while((pListHeadLong != nullptr) && (pListHeadShort != nullptr) && (pListHeadShort != pListHeadLong)) + { + pListHeadLong = pListHeadLong->next; + pListHeadShort = pListHeadShort->next; + } + + //得到第一个公共节点 + ListNode *pFirstCommonNode = pListHeadLong; + + return pFirstCommonNode; + +} + + +//得到链表的长度 +unsigned int getListLength(ListNode *pHead) +{ + unsigned int nLength = 0; + ListNode *pNode = pHead; + + while(pNode != nullptr) { + ++nLength; + pNode = pNode->next; + } + + return nLength; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex53.cc" "b/\345\211\221\346\214\207Offer/ex53.cc" new file mode 100755 index 0000000..e09c192 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex53.cc" @@ -0,0 +1,241 @@ + + +/* + 面试题53:在排序数组中查找数字 + 注意:只要题目中涉及到了排序数组,一般都是考察二分查找 +*/ + + +#include + +int getFirstK(int *data, int length, int k, int start, int end); +int getLastK(int *data, int length, int k, int start, int end); +int getNumberOfK(int *data, int length, int k); + +int getMissingNumber(const int *numbers, int length); + +int getNumberSameAsIndex(const int *numbers, int length); + + +int main(){ + int data[] = {-3,-1,1,3,5}; + int n = sizeof(data)/sizeof(data[0]); + + // std::cout << getNumberOfK(data, n, 4) << std::endl; + // std::cout << getMissingNumber(data, n) << std::endl; + std::cout << getNumberSameAsIndex(data, n) << std::endl; + + return 0; +} + + +int getFirstK(int *data, int length, int k, int start, int end) +{ + if(start > end) return -1; //数组中不包含k则返回-1 + + int midIndex = (start + end)/2; + int midData = data[midIndex]; + + if(midData == k) + { + //如果中间数字等于k,判断前面一个数是否也等于k + if((midIndex > 0 && data[midIndex-1] != k) || midIndex == 0) { + return midIndex; + } + else { + end = midIndex - 1; + } + } + else if(midData > k) { //二分法更新起点start和终点end + end = midIndex - 1; + } + else { + start = midIndex + 1; + } + + return getFirstK(data, length, k, start, end); + +} + + +int getLastK(int *data, int length, int k, int start, int end) +{ + if(start > end) return -1; + + int midIndex = (start + end)/2; + int midData = data[midIndex]; + + if(midData == k) + { + if((midIndex < length-1 && data[midIndex+1] != k) || midIndex == length-1) { + return midIndex; + } + else { + start = midIndex + 1; + } + } + else if(midData < k) { + start = midIndex + 1; + } + else { + end = midIndex - 1; + } + + return getLastK(data, length, k, start, end); + +} + + +int getNumberOfK(int *data, int length, int k) +{ + int number = 0; + + if(data != nullptr && length > 0) + { + int first = getFirstK(data, length, k, 0, length-1); + int last = getLastK(data, length, k, 0, length-1); + + if(first > -1 && last > -1) { + number = last - first + 1; + } + } + + return number; + +} + + +//C++解法 + +int GetNumberOfTarget(std::vector &nums, int target) +{ + if(nums.empty()) return 0; + + int first = GetFirstTarget(nums, 0, nums.size() - 1, target); + int last = GetLastTarget(nums, 0, nums.size() - 1, target); + + if(first == -1 || last == -1) { + return 0; + } + + return last - first + 1; +} + + +int GetFirstTarget(std::vector &nums, int left, int right, int target) +{ + //未找到目标则返回-1 + if(left > right) return -1; + + int midIndex = left + ((right - left) >> 1); + int midData = nums[midIndex]; + + if(midData == target) { + if((midIndex > 0 && nums[midIndex-1] != target) || midIndex == 0) { + return midIndex; + } + else { + right = midIndex - 1; + } + } + else if(midData > target) { + right = midIndex - 1; + } + else { + left = midIndex + 1; + } + + return GetFirstTarget(nums, left, right, target); +} + +int GetLastTarget(std::vector &nums, int left, int right, int target) +{ + //未找到目标则返回-1 + if(left > right) return -1; + + int midIndex = left + ((right - left) >> 1); + int midData = nums[midIndex]; + + if(midData == target) { + if((midIndex < nums.size()-1 && nums[midIndex+1] != target) || midIndex == nums.size() -1 ) { + return midIndex; + } + else { + left = midIndex + 1; + } + } + else if(midData > target) { + right = midIndex - 1; + } + else { + left = midIndex + 1; + } + + return GetLastTarget(nums, left, right, target); +} + + + + + + + +//题目二:0~n-1中缺失的数字 + +int getMissingNumber(const int *numbers, int length) +{ + if(numbers == nullptr || length <= 0) return -1; + + int left = 0; + int right = length - 1; + while(left <= right) + { + int middle = (left + right)>>1; + if(numbers[middle] != middle) + { + if(middle == 0 || numbers[middle-1] == middle-1) return middle; + + right = middle - 1; + } + else + { + left = middle + 1; + } + + } + + //如果不缺失,则返回的是数组个数 + if(left == length) return length; + + return -1; + +} + + + +//题目三:数组中数值和下标相等的元素 + +int getNumberSameAsIndex(const int *numbers, int length) +{ + if(numbers == nullptr || length <= 0) return -1; + + int left = 0; + int right = length - 1; + + while(left <= right) + { + int middle = (left + right)/2; + + if(numbers[middle] == middle) return middle; + + if(numbers[middle] > middle) { + right = middle -1; + } + else { + left = middle + 1; + } + + } + + return -1; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex54.cc" "b/\345\211\221\346\214\207Offer/ex54.cc" new file mode 100755 index 0000000..52b8d80 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex54.cc" @@ -0,0 +1,46 @@ + + +/* + 面试题54:二叉搜索树的第k大节点 + 考察中序遍历 +*/ + + +struct binaryTeeNode{ + int value; + binaryTeeNode *pLeft; + binaryTeeNode *pRight; +}; + + +binaryTeeNode* kthNode(binaryTeeNode *pRoot, unsigned int k) +{ + if(pRoot == nullptr || k == 0) return nullptr; + + return kthNodeCore(pRoot, k); + +} + + +binaryTeeNode *kthNodeCore(binaryTeeNode *pRoot, unsigned int &k) +{ + binaryTeeNode *target = nullptr; + if(pRoot->pLeft != nullptr) { + target = kthNodeCore(pRoot->left, k); + } + + if(target == nullptr) + { + if(k == 1) { + target = pRoot; + } + + k--; + } + + if(target == nullptr && pRoot->pRight != nullptr) { + target = kthNodeCore(pRoot->pRight, k); + } + + return target; +} diff --git "a/\345\211\221\346\214\207Offer/ex55.cc" "b/\345\211\221\346\214\207Offer/ex55.cc" new file mode 100755 index 0000000..01db0ce --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex55.cc" @@ -0,0 +1,68 @@ + + +/* + 面试题55:二叉树的深度 +*/ + + +//思路:分情况 +//1.二叉树只有一个根节点,则深度为1 +//2.二叉树只有左子树没有右子树,则深度为左子树的深度+1 +//3.二叉树只有右子树没有左子树,则深度为右子树的深度+1 +//4.二叉树既有左子树又有右子树,则深度为左子树的深度+右子树的深度+1 + + +struct binaryTreeNode{ + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +int treeDepth(binaryTreeNode *root) +{ + if(root == nullptr) return 0; + + int nLeft = treeDepth(root->left); + int nRight = treeDepth(root->right); + + return (nLeft > nRight) ? (nLeft + 1) : (nRight + 1); + +} + + + +//附:判断一颗二叉树是不是平衡二叉树 +//思路:也可以按照上面计算二叉树的深度代码来实现;但是存在一个节点需要遍历多次 +//如果采用后序遍历,那么每个节点只需遍历一次,边遍历边记录每个节点的深度 + +bool isBalanced(binaryTreeNode *root) +{ + int depth = 0; + + return isBalancedCore(root, &depth); +} + + +bool isBalancedCore(binaryTreeNode *root, int *depth) +{ + if(root == nullptr) { + *depth = 0; + return true; + } + + int left, right; + if(isBalancedCore(root->left, &left) && isBalancedCore(root->right, &right)) + { + int diff = left-right; + if(diff <= 1 && diff >= -1) { + *depth = 1 + (left > right) ? left : right; + return true; + } + + } + + return false; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex56.cc" "b/\345\211\221\346\214\207Offer/ex56.cc" new file mode 100755 index 0000000..3c803d7 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex56.cc" @@ -0,0 +1,120 @@ + + +/* + 面试题56:数组中数字出现的次数 + + 1.给定一个数组,其中有两个元素只出现一次,其余元素出现多次;找出这两个只出现一次的元素 + + 2.在一个数组中只有一个元素出现了一次,其余元素都出现了三次,找出这个只出现一次的元素 +*/ + + + +#include + +void findNumsApperOnce(int data[], int length, int *num1, int *num2); +unsigned int findFirstBitIs1(int num); +bool isBit1(int num, unsigned int indexBit); + +int findNumsAppearingOnce(int numbers[], int length); + + +int main(){ + + int numbers[] = {1,1,1,3}; + int length = sizeof(data)/sizeof(data[0]); + + std::cout << findNumsAppearingOnce(data, length) << std::endl; + + return 0; +} + + + +void findNumsApperOnce(int data[], int length, int *num1, int *num2) +{ + if(data == nullptr || length < 2) return; + + int resultExclusive = data[0]; + for(int i = 1; i < length; i++) { + resultExclusive ^= data[i]; + } + + unsigned int indexOf1 = findFirstBitIs1(resultExclusive); + + //这里这两个数必须要赋值,否则下面第一次异或的结果不确定; + //0与num异或的结果还是num; 即 0^num = num + *num1 = *num2 = 0; + for(int j = 0; j < length; j++) + { + if(isBit1(data[j], indexOf1)) { + *num1 ^= data[j]; + } + else { + *num2 ^= data[j]; + } + } + +} + + +//在整数num的二进制表示中找到最右边第一个是1的位 +unsigned int findFirstBitIs1(int num) +{ + int indexBit = 0; + + //第二个语句是避免无限的右移导致溢出,比如num=0的情况,第一个条件(num&1)==0永远满足 + while((num & 1) == 0 && (indexBit < 8*sizeof(int))) //千万不要写成 num & 1 == 0, "&"的优先级比"=="低 + { + num = num >> 1; + ++indexBit; + } + + return indexBit; +} + +//判断整数num的二进制表示中从最右边数的indexBit位是否为1 +bool isBit1(int num, unsigned int indexBit) +{ + num = num >> indexBit; + + return(num & 1); +} + + + +int findNumsAppearingOnce(int numbers[], int length) +{ + if(numbers == nullptr || length <= 0) { + std::cout << "Invalid Input!" << std::endl; + exit(1); + } + + //int型的数据占4字节,也就是32位 + int bitSum[32] = {0}; + for(int i = 0; i < length; i++) + { + int bitMask = 1; + for(int j = 31; j >= 0; j--) + { + int bit = numbers[i] & bitMask; + if(bit != 0) { + bitSum[j] += 1; + } + + bitMask = bitMask << 1; //注意:在Leetcode第137题中,这样写会报错溢出;可以改写为 nums[i] = nums[i] >> 1; + } //将nums[i]右移的效果和bitMask左移的效果是一样的 + + } + + int result = 0; + for(int i = 0; i < 32; i++) + { + result = result << 1; + result += bitSum[i] % 3; + + } + + return result; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex57.cc" "b/\345\211\221\346\214\207Offer/ex57.cc" new file mode 100755 index 0000000..41779ab --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex57.cc" @@ -0,0 +1,162 @@ + +/* + 面试题57:和为s的数字 +*/ + +//思路:利用双指针法,当两指针指向元素之和大于给定值,则将尾指针前移,小于给定值将首指针后移 + + +#include + +bool findNumbersWithSum(int data[], int length, int sum, int *num1, int *num2); + +void findContinuousSequence(int sum); +void printContinuousSequence(int small, int big); + + +int main(){ + int data[] = {1,2,4,7,11,15}; + int n = sizeof(data)/sizeof(data[0]); + // int *num1 = new int(0); + // int *num2 = new int(0); + int num1, num2; + + if(findNumbersWithSum(data, n, 15, num1, num2)) { + std::cout << *num1 << std::endl; + std::cout << *num2 << std::endl; + } + + delete num1; + delete num2; + + // findContinuousSequence(14); + + return 0; +} + + +bool findNumbersWithSum(int data[], int length, int sum, int *num1, int *num2) +{ + bool found = false; + if(length < 1 || num1 == nullptr || num2 == nullptr) return found; + + int right = length - 1; + int left = 0; + + while(right > left) + { + int curSum = data[left] + data[right]; //没必要使用long long型,下面的if判断语句拿long和int比较没有意义 + + if(curSum == sum) + { + *num1 = data[left]; + *num2 = data[right]; + found = true; + break; + } + else if(curSum > sum) { + right--; + } + else { + left++; + } + + } + + return found; + +} + + + +//题目二:和为s的连续正序列 + +void findContinuousSequence(int sum) +{ + //两个连续正数的最小和为3 + if(sum < 3) return; + + int small = 1; + int big = 2; + int middle = (1 + sum)/2; //small的上限(取不到) + int curSum = small + big; + + while(small < middle) + { + if(curSum == sum) { + printContinuousSequence(small, big); + } + + while(curSum > sum && small < middle) + { + curSum -= small; + small++; + + if(curSum == sum) { + printContinuousSequence(small, big); + } + } + + big++; + curSum += big; + + } + +} + + +void printContinuousSequence(int small, int big) +{ + for(int i = small; i <= big; i++) { + printf("%d ", i); + } + + printf("\n"); +} + + +//C++写法 + +std::vector> continueSubsequences(int target) +{ + std::vector> res; + + if(target < 3) return res; + + int small = 1, big = 2; + int middle = (target + 1)/2; + int curSum = small + big; + + while(small < middle) + { + if(curSum == target) { + res.push_back(subsequence(small, big)); + } + + while(curSum > target && small < middle) + { + curSum -= small; + small++; + + if(curSum == target) { + res.push_back(subsequence(small, big)); + } + } + + big++; + curSum += big; + } + + return res; +} + +std::vector subsequence(int low, int hig) +{ + std::vector res; + + for(int i = low; i <= hig; i++) { + res.push_back(i); + } + + return res; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex58.cc" "b/\345\211\221\346\214\207Offer/ex58.cc" new file mode 100755 index 0000000..4eddd58 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex58.cc" @@ -0,0 +1,113 @@ + +/* + 第58题:翻转字符串 + //参考Leetcode第151题 +*/ + + +#include +#include + +void reverse(char *pBegin, char *pEnd); +char *reverseSentence(char *pData); +char *leftRotateString(char *ptr, int n); + + +int main(){ + // char str[] = ""; + // char *p = reverseSentence(str); + + // std::cout << p << std::endl; + + char str[] = "abcdefg"; + char *p = leftRotateString(str, 2); + + std::cout << p << std::endl; + + return 0; +} + +void reverse(char *pBegin, char *pEnd) +{ + if(pBegin == nullptr || pEnd == nullptr){ + return; + } + + while(pBegin < pEnd) + { + char tmp = *pBegin; + *pBegin = *pEnd; + *pEnd = tmp; + + pBegin++; + pEnd--; + } + +} + + +//翻转单词顺序 + +char *reverseSentence(char *pData) +{ + if(pData == nullptr) return nullptr; + + char *pBegin = pData; + char *pEnd = pData; + while(*pEnd != '\0'){ + pEnd++; + } + --pEnd; + + reverse(pBegin, pEnd); //翻转整个句子 + + pBegin = pEnd = pData; //翻转每个单词 + while(*pBegin != '\0') + { + //去除翻转整个句子后首部的空格 + if(*pBegin == ' ') { + pBegin++; + pEnd++; + } + else if(*pEnd == ' ' || *pEnd == '\0') { + reverse(pBegin, --pEnd); + pBegin = ++pEnd; + } + else { + pEnd++; + } + + } + + return pData; +} + + + + +//左旋转字符串 + +char *leftRotateString(char *ptr, int n) +{ + if(ptr == nullptr) return nullptr; + + int len = static_cast(strlen(ptr)); //使用strlen需要包含头文件但是C++将头文件全部转换成为 + if(len == 0 || n <= 0 || n >= len) return ptr; + + char *pFirstStart = ptr; + char *pFirstEnd = ptr + n - 1; + char *pSecondStart = ptr + n; + char *pSecondEnd = ptr + len - 1; + + //翻转字符串的前n个字符 + reverse(pFirstStart, pFirstEnd); + + //翻转字符串的后面部分 + reverse(pSecondStart, pSecondEnd); + + //翻转整个字符串 + reverse(pFirstStart, pSecondEnd); + + return ptr; + +} diff --git "a/\345\211\221\346\214\207Offer/ex59.cc" "b/\345\211\221\346\214\207Offer/ex59.cc" new file mode 100755 index 0000000..626cc90 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex59.cc" @@ -0,0 +1,70 @@ + + + +/* + 面试题59:队列的最大值 +*/ + +#include +#include +#include + +std::vector maxInWindows(const std::vector &num, unsigned int size); + +int main(){ + std::vector num = {2,3,4,2,6,2,5,1}; + + std::vector window = maxInWindows(num, 3); + + for(int n:window) { + std::cout << n << " "; + } + std::cout << std::endl; + + return 0; +} + + +std::vector maxInWindows(const std::vector &num, unsigned int size) +{ + std::vector maxInWindows; + + if(num.size() >= size && size >= 1) + { + std::deque index; + + //找到第一次滑动窗口中的最大元素 + for(unsigned int i = 0; i < size; i++) + { + while(!index.empty() && num[i] >= num[index.back()]) { + index.pop_back(); + } + + index.push_back(i); + } + + for(unsigned int i = size; i < num.size(); i++) + { + maxInWindows.push_back(num[index.front()]); + + //存入index队列中的元素是单调递减的 + while(!index.empty() && num[i] >= num[index.back()]) { + index.pop_back(); + } + + //滑动窗口移动后,判断队首的元素是否还在窗口中 + if(!index.empty() && index.front() <= (int)(i-size)) { + index.pop_front(); + } + + index.push_back(i); + } + + //这是存储的最后一次窗口中的最大数值 + maxInWindows.push_back(num[index.front()]); + + } + + return maxInWindows; + +} diff --git "a/\345\211\221\346\214\207Offer/ex6.cc" "b/\345\211\221\346\214\207Offer/ex6.cc" new file mode 100755 index 0000000..8b804bb --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex6.cc" @@ -0,0 +1,50 @@ + + +/* + 面试题6:输入链表的头结点,从尾到头打印每个节点的值 +*/ + + +#include + +struct ListNode +{ + int value; + ListNode *next; +}; + + +//方法一:使用栈 +void PrintListReversingly_Iteratively(ListNode *pHead) +{ + std::stack nodes; //定义一个栈 + + ListNode *pNode = pHead; + while(pNode != NULL){ //将链表中的节点存入栈中 + nodes.push(pNode); + pNode = pNode->next; + } + + while(!nodes.empty()){ + pNode = nodes.top(); + std::cout << pNode->value << " "; + nodes.pop(); + } + +} + + + + +//方法二:使用递归 +void PrintListReversingly_Recursively(ListNode *pHead) +{ + if(pHead != NULL){ + if(pHead->next != NULL){ + PrintListReversingly_Recursively(pHead->next); + } + std::cout << pHead->value; + } + + +} diff --git "a/\345\211\221\346\214\207Offer/ex60.cc" "b/\345\211\221\346\214\207Offer/ex60.cc" new file mode 100755 index 0000000..5b4d19c --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex60.cc" @@ -0,0 +1,131 @@ + + +/* + 面试题60:n个骰子的点数 + + 使用循环的解法会比使用递归的解法要好 +*/ + + +#include +#include + +int g_maxValue = 6; +void printProbability(int number); +void Probability(int number, int *pProbabilities); +void Probability(int original, int current, int sum, int *pProbabilities); + + +int main(){ + printProbability(11); + + return 0; +} + + +//方法一:使用递归 + +void printProbability(int number) +{ + if(number < 1) return; + + int maxSum = number*g_maxValue; + int *pProbabilities = new int[maxSum - number + 1]; + + for(int i = number; i <= maxSum; i++) { + pProbabilities[i-number] = 0; + } + + Probability(number, pProbabilities); + + int total = pow((double)g_maxValue, number); + for(int i = number; i <= maxSum; i++) + { + double ratio = (double)pProbabilities[i-number]/total; + printf("%d: %e\n", i, ratio); + } + + delete[] pProbabilities; + +} + + +void Probability(int number, int *pProbabilities) +{ + for(int i = 1; i <= g_maxValue; i++) { + Probability(number, number, i, pProbabilities); + } + +} + + +void Probability(int original, int current, int sum, int *pProbabilities) +{ + if(current == 1) + { + pProbabilities[sum-original]++; + } + else + { + for(int i = 1; i <= g_maxValue; i++) { + Probability(original, current-1, i+sum, pProbabilities); + } + } + +} + + + + +//方法二:使用循环 + +void printProbability(int number) +{ + if(number < 1) return; + + int *pProbabilities[2]; + pProbabilities[0] = new int[g_maxValue * number + 1]; + pProbabilities[1] = new int[g_maxValue * number + 1]; + + for(int i = 0; i < g_maxValue*number + 1; i++) + { + pProbabilities[0][i] = 0; + pProbabilities[1][i] = 0; + } + + int flag = 0; + + for(int i = 1; i <= g_maxValue; i++) { + pProbabilities[flag][i] = 1; + } + + for(int k = 2; k <= number; k++) + { + for(int i = 0; i < k; i++) { + pProbabilities[1-flag][i] = 0; + } + + for(int i = k; i <= g_maxValue*k; i++) + { + pProbabilities[1-flag][i] = 0; + for(int j = 1; j <= i && j <= g_maxValue; j++) { + pProbabilities[1-flag][i] += pProbabilities[flag][i-j]; + } + } + + flag = 1-flag; + } + + double total = pow((double)g_maxValue, number); + + for(int i = number; i <= g_maxValue*number; i++) + { + double ratio = (double)pProbabilities[flag][i]/total; + printf("%d: %e\n", i, ratio); //如果这里不使用%e格式输出,而使用%f格式输出,则当色子个数很多时,这个数很小就会被自动舍去了 + } + + + delete[] pProbabilities[0]; + delete[] pProbabilities[1]; + +} diff --git "a/\345\211\221\346\214\207Offer/ex61.cc" "b/\345\211\221\346\214\207Offer/ex61.cc" new file mode 100755 index 0000000..3c96d3d --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex61.cc" @@ -0,0 +1,104 @@ + + + +/* + 面试题61:扑克牌中的顺子 + 这题重在题意的理解 +*/ + + +#include +#include +#include + +bool isContinuous(int *numbers, int length); +int compare(const void *arg1, const void *arg2); + +bool isContinuous(std::vector &numbers); + + +int main(){ + int numbers[] = {0,1,3,4,5}; + int length = sizeof(numbers)/sizeof(numbers[0]); + + std::cout << isContinuous(numbers, length) << std::endl; + + std::vector number = {0,1,3,4,5}; + std::cout << isContinuous(number) << std::endl; + + return 0; +} + + +//C语言解法 + +bool isContinuous(int *numbers, int length) +{ + if(numbers == nullptr || length < 1) return false; + + qsort(numbers, length, sizeof(int), compare); + + int numberOfZero = 0; + int numberOfGap = 0; + + //统计数组中0的个数 + for(int i = 0; i < length && numbers[i] == 0; i++) { + numberOfZero++; + } + + //统计数组中间隔的数目 + int small = numberOfZero; + int big = small+1; + while(big < length) + { + if(numbers[small] == numbers[big]) return false; + + numberOfGap += numbers[big]-numbers[small]-1; + small = big; + ++big; + } + + return (numberOfZero > numberOfGap) ? false : true; + +} + +int compare(const void *arg1, const void *arg2) +{ + return *(int*)arg1 - *(int*)arg2; +} + + + +//C++解法 + +bool isContinuous(std::vector &numbers) +{ + if(numbers.empty()) return false; + + sort(numbers.begin(), numbers.end()); + + int length = numbers.size(); + + int numberOfZero = 0; + int numberOfGap = 0; + + //统计数组中0的个数 + for(int i = 0; i < length && numbers[i] == 0; i++) { + numberOfZero++; + } + + //统计数组中间隔的数目 + int small = numberOfZero; + int big = small+1; + while(big < length) + { + if(numbers[small] == numbers[big]) return false; + + numberOfGap += numbers[big]-numbers[small]-1; + small = big; + ++big; + } + + return (numberOfZero > numberOfGap) ? false : true; + +} diff --git "a/\345\211\221\346\214\207Offer/ex62.cc" "b/\345\211\221\346\214\207Offer/ex62.cc" new file mode 100755 index 0000000..5c31085 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex62.cc" @@ -0,0 +1,66 @@ +/* + 面试题62:圆圈中最后剩下的一个数字 (约瑟夫环问题) + +*/ + + + +//使用环形链表解决 + +int lastRemaining(unsigned int n, unsigned int m) +{ + if(n < 1 || m < 1) return -1; + + unsigned int i = 0; + std::list numbers; + + for(i = 0; i < n; i++) + { + numbers.push_back(i); + } + + std::list::iterator current = numbers.begin(); + + while(numbers.size() > 1) + { + for(int i = 1; i < m; i++) + { + current++; + if(current == numbers.end()){ + current == numbers.begin(); + } + } + + std::listiterator next = current++; + if(next == numbers.end()) { + next = numbers.begin(); + } + + current--; + numbers.erase(current); + current = next; + + } + + return *current; + +} + + + + +//找规律,使用迭代 + +int lastRemaining(unsigned int n, unsigned int m) +{ + if(n < 1 || m < 1) return -1; + + int last = 0; + for(int i = 2; i <= n; i++) + { + last = (last+m)%i; + } + + return last; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex63.cc" "b/\345\211\221\346\214\207Offer/ex63.cc" new file mode 100755 index 0000000..b951eca --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex63.cc" @@ -0,0 +1,53 @@ + + +/* + 面试题53:股票的最大利润 + 参考Leetcode第121题 +*/ + +//思路: +//遍历到第i个数字时,与前面i-1个数字的最小值做差就能得到该价位卖出时的利润,将该利润与之前价位的最大利润比较 +//遍历到数组末尾取最大利润值即可 + +int maxDiff(const int *numbers, unsigned int length) +{ + if(numbers == nullptr || length <= 1) return 0; + + int min = numbers[0]; + int maxDiff = numbers[1] - min; + + for(int i = 2; i < length; i++) + { + //保存前i-1数字的最小值 + if(numbers[i-1] < min) { + min = numbers[i-1]; + } + + //当前利润与最大利润比较 + int curDiff = numbers[i] - min; + if(curDiff > maxDiff) { + maxDiff = curDiff; + } + + } + + return maxDiff; + +} + + +int maxProfit(std::vector &prices) +{ + if(prices.size() <= 1) return 0; + + int minPrice = prices[0]; + int maxProfit = 0; + + for(int i = 1; i < prices.size(); i++) { + minPrice = std::min(minPrice, prices[i]); + maxProfit = std::max(maxProfit, prices[i] - minPrice); + } + + return maxProfit; + +} diff --git "a/\345\211\221\346\214\207Offer/ex64.cc" "b/\345\211\221\346\214\207Offer/ex64.cc" new file mode 100755 index 0000000..e0d5b2b --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex64.cc" @@ -0,0 +1,131 @@ + + +/* + 面试题64:求1+2+3+...+n +*/ + +//解法一:使用构造函数 + +class Temp +{ + public: + Temp() { + ++N; + Sum += N; + } + + static int Reset() { + N = 0; + Sum = 0; + } + + static unsigned int GetSum() { + return Sum; + } + + private: + static unsigned int N; + static unsigned int Sum; + +}; + + +unsigned int Temp::N = 0; +unsigned int Temp::Sum = 0; + +unsigned int Sum_Solution1(unsigned int n) +{ + Temp::Reset(); + + Temp *a = new Temp[n]; + delete[] a; + a = nullptr; //防止其成为悬空指针 + + return Temp::GetSum(); +} + + + +//解法二:利用虚函数求解 + +class A; +A* Array[2]; + +class A +{ + public: + virtual unsigned int Sum(unsigned int n) { + return 0; + } + +}; + + +class B : public A +{ + public: + virtual unsigned int Sum(unsigned int n) { + return Array[!!n]->Sum(n-1) + n; + } + +}; + + +int Sum_Solution2(int n) +{ + A a; + B b; + Array[0] = &a; + Array[1] = &b; + + int value = Array[1]->Sum(n); + + return value; + +} + + + +//解法三:利用函数指针来求解 + +typedef unsigned int(*fun)(unsigned int); + +unsigned int Soluton3_Teminator(unsigned int n) +{ + return 0; +} + +unsigned int Sum_Solution3(unsigned int n) +{ + static fun f[2] = {Soluton3_Teminator, Sum_Solution3}; + + return n + f[!!n](n-1); +} + + + +//解法四:利用模板类型求解 + +template struct Sum_Solution4 +{ + enum Value { N = Sum_Solution4::N + n }; +}; + +template<> struct Sum_Solution4<1> +{ + enum Value { N = 1 }; +}; + + + +#include + +int main(){ + std::cout << Sum_Solution1(100) << std::endl; + std::cout << Sum_Solution2(100) << std::endl; + std::cout << Sum_Solution3(100) << std::endl; + std::cout << Sum_Solution4<100>::N << std::endl; + + return 0; +} + diff --git "a/\345\211\221\346\214\207Offer/ex65.cc" "b/\345\211\221\346\214\207Offer/ex65.cc" new file mode 100755 index 0000000..2e2b3b3 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex65.cc" @@ -0,0 +1,49 @@ + + +/* + 面试题65:不用加减乘除做加法 +*/ + + +#include + +int add(int num1, int num2); + +int main(){ + + std::cout << add(-17, -5) << std::endl; + + return 0; +} + +int add(int num1, int num2) +{ + int sum; + int carry; + + do{ + sum = num1^num2; + carry = (num1&num2)<<1; + num1 = sum; + num2 = carry; + + }while(num2 != 0); + + return num1; + +} + +//Leetcode第371题 +int getSum(int a, int b) +{ + int sum, carry; + while(b) { + sum = a^b; + carry = (unsigned)(a&b)<<1; //这里的作用是将最高位符号位置0,以防止存在负数导致溢出 + a = sum; + b = carry; + } + + return a; +} + diff --git "a/\345\211\221\346\214\207Offer/ex66.cc" "b/\345\211\221\346\214\207Offer/ex66.cc" new file mode 100755 index 0000000..899e176 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex66.cc" @@ -0,0 +1,50 @@ + + +/* + 面试题66:构建乘积数组 +*/ + + +#include +#include + +void multiply(const std::vector &array1, std::vector &array2); + + +int main(){ + std::vector array1 = {1,2,3,4}; + std::vector array2(array1.size(), 0); + + //注意:上面array2在传入该函数之前必须初始化,因为函数内部存在两个容器的判断语句: length1 == length2 + multiply(array1, array2); + + for(double num:array2) { + std::cout << num << " "; + } + std::cout << std::endl; + + return 0; +} + + +void multiply(const std::vector &array1, std::vector &array2) +{ + int length1 = array1.size(); + int length2 = array2.size(); + + if(length1 == length2 && length2 > 1) + { + array2[0] = 1; + for(int i = 1; i < length1; i++) { + array2[i] = array2[i-1] * array1[i-1]; + } + + double temp = 1; + for(int i = length1-2; i >= 0; i--) { + temp *= array1[i+1]; + array2[i] *= temp; + } + + } + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/ex67.cc" "b/\345\211\221\346\214\207Offer/ex67.cc" new file mode 100755 index 0000000..c090010 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex67.cc" @@ -0,0 +1,132 @@ + + +/* + 面试题67:实现atoi函数 + 参考Leetcode第8题,该题实现了atoi的所有功能 +*/ + +//这个例题字符串开头和末尾不能输入空格 +//但是实际的atoi函数中的字符串开头可以输入空格 + +#include +#include + +enum status {kvalid = 0, kInvalid}; +int g_nStatus = kvalid; + +int strToInt(const char *str); +long long strToIntCore(const char *digit, bool minus); + +int main(){ + char str[] = "-123"; + std::cout << strToInt(str) << std::endl; + + return 0; +} + +int strToInt(const char *str) +{ + g_nStatus = kInvalid; + long long num = 0; + + if(str != nullptr && *str != '\0') + { + bool minus = false; + if(*str == '+') { + str++; + } + else if(*str == '-') { + str++; + minus = true; + } + + if(*str != '\0') + { + num = strToIntCore(str, minus); + } + + } + + return (int)num; + +} + +long long strToIntCore(const char *digit, bool minus) +{ + long long num = 0; + + while(*digit != '\0') + { + if(*digit >= '0' && *digit <= '9') + { + int flag = minus ? -1 : 1; + num = num*10 + flag*(*digit - '0'); + + if((!minus && num > INT_MAX) || (minus && num < INT_MIN)) + { + num = 0; + break; + } + + digit++; + } + else + { + num = 0; + break; + } + + } + + if(*digit == '\0') { + g_nStatus = kvalid; + } + + return num; + +} + + +//C++的写法 +//当输入的字符串为空时,显示报错并且返回0 + +int strToInt(std::string str) +{ + if(str.empty()) { + std::cout << "Invalid Input!" << std::endl; + return 0; + } + + long long num = 0; + int index = 0; + bool minus = false; + + if(str[index] == '+' || str[index] == '-') { + minus = (str[index] == '-') ? true : false; + index++; + } + + while(index < str.size()) + { + if(str[index] >= '0' && str[index] <= '9') + { + int flag = minus ? -1 : 1; + num = num*10 + flag*(str[index]- '0'); + + if((!minus && num > INT_MAX) || (minus && num < INT_MIN)) { + std::cout << "Invalid Input!" << std::endl; + return 0; + } + + index++; + } + else + { + std::cout << "Invalid Input!" << std::endl; + return 0; + } + + } + + return (int)num; +} diff --git "a/\345\211\221\346\214\207Offer/ex7.cc" "b/\345\211\221\346\214\207Offer/ex7.cc" new file mode 100755 index 0000000..43ac504 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex7.cc" @@ -0,0 +1,161 @@ + + +/* + 面试题7:重建二叉树 +*/ + + +struct binaryTreeNode { + int val; + binaryTreeNode *left; + binaryTreeNode *right; + +}; + + +binaryTreeNode* construct(int *preorder, int *inorder, int length) +{ + if(preorder == nullptr || inorder == nullptr || length <= 0) return nullptr; + + return constructCore(preorder, preorder+length-1, inorder, inorder+length-1); + +} + +binaryTreeNode *constructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder) +{ + //前序遍历的第一个节点就是根节点的数值 + int rootValue = startInorder[0]; + + binaryTreeNode *root = new binaryTreeNode(); + root->val = rootValue; + root->left = root->right = nullptr; + + //如果前序序列元素只有一个 + if(startPreorder == endPreorder) + { + //如果前序遍历只有一个元素,中序遍历也只有一个元素;说明该树只有一个节点 + //并且如果前序遍历的这个元素和中序遍历的这个元素的值相等,则返回根节点 + //否则返回错误信息 + if(startPreorder == endPreorder && *startPreorder == *startInorder) { + return root; + } + else { + std::cout << "Invalid input!" << std::endl; + exit(1); + } + + } + + + //下面的情况为前序序列的元素不只一个 + + //在中序遍历中找到根节点的位置 + int *rootInorder = startInorder; + while(rootInorder < endInorder && *rootInorder != rootValue) { + rootInorder++; + } + + //如果在中序遍历中找到末尾了还没有找到根节点,说明中序遍历输入有错;直接返回错误信息 + if(rootInorder == endInorder && *rootInorder != rootValue) { + std::cout << "Invalid input!" << std::endl; + exit(1); + } + + int leftLength = rootInorder - startInorder; //得到根节点左子树的长度 + int *leftPreorderEnd = startPreorder + leftLength; //得到左子树在前序序列中结束的位置 + + //构建左子树 + if(leftLength > 0) + { + root->left = constructCore(startPreorder+1, leftPreorderEnd, startInorder, rootInorder-1); + } + + //构建右子树 + //endProrder-startInorder得到的长度是树中除去根节点的所有节点的数量;也就是左子树和右子树的长度之和 + if(leftLength < endPreorder-startPreorder) + { + root->right = constructCore(leftPreorderEnd+1, endPreorder, rootInorder+1, endInorder); + } + + + return root; +} + + + +//以下为Leetcode第105题的依据前序遍历和中序遍历重建二叉树和第106题的依据后序和中序遍历重建二叉树 + + +struct TeeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode () : val(0), left(nullptr), right(nullptr) {} + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + TreeNode(int x, TreeNode *left, TreeNode *right) : val(x) , left(left), right(right) {} +}; + + +// 根据前序和中序遍历来重建二叉树 +TreeNode* buildTree(std::vector &preorder, std::vector &inorder) +{ + std::unordered_map inorderPos; + for(int i = 0; i < inorder.size(); i++) { + inorderPos[inorder[i]] = i; + } + + return buildTreeCore(preorder, 0, preorder.size() - 1, 0, inorderPos); +} + + +//这里定义startInorder是为了在重建的过程中得到左右子树的长度 +TreeNode* buildTreeCore(std::vector &preorder, int startPreorder, int endPreorder, int startInorder, std::unordered_map &inorderPos) +{ + if(startPreorder > endPreorder) return nullptr; + + TreeNode *root = new TreeNode(preorder[startPreorder]); + + int rootIndex = inorderPos[preorder[startPreorder]]; + + int leftLen = rootIndex - startInorder; + + root->left = buildTreeCore(preorder, startPostorder + 1, startPreorder + leftLen, startInorder, inorderPos); + + root->right = buildTreeCore(preorder, startPreorder + leftLen + 1, endPreorder, rootIndex + 1, inorderPos); + + return root; +} + + + +//依据后序和中序遍历来重建二叉树 +TreeNode* buildTree(std::vector &postorder, std::vector &inorder) +{ + std::unordered_map inorderPos; + for(int i = 0; i < inorder.size(); i++) { + inorderPos[inorder[i]] = i; + } + + return buildTreeCore(postorder, 0, postorder.size() - 1, 0, inorderPos); +} + +TreeNode *buildTreeCore(std::vector &postorder, int startPostorder, int endPostorder, int startInorder, std::unordered_map &inorderPos) +{ + if(startPostorder > endPostorder) return nullptr; + + TreeNode *root = new TreeNode(postorder[endPostorder]); + + int rootIndex = inorderPos[postorder[endPostorder]]; + + int leftLen = rootIndex - startInorder; + + root->left = buildTreeCore(postorder, startPostorder, startPostorder + leftLen - 1, startInorder, inorderPos); + + root->right = buildTreeCore(postorder, startPostorder + leftLen, endPostorder - 1, rootIndex + 1, inorderPos); + + return root; +} + + + + diff --git "a/\345\211\221\346\214\207Offer/ex8.cc" "b/\345\211\221\346\214\207Offer/ex8.cc" new file mode 100755 index 0000000..d362be7 --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex8.cc" @@ -0,0 +1,137 @@ + + +/* + 面试题8:二叉树的下一个节点 + 找出中序遍历序列的下一个节点 + //题目出的非常好 +*/ + +//思路:分两种情况 +//1.如果节点有右子树,则其下一个节点就是它的右子树的最左子节点 +//2.1.如果节点没有右子树,并且该节点是它父节点的左子节点,则其下一个节点就是它的父节点 +//2.2.如果节点没有右子树,并且该节点是它父节点的右子节点,则需要沿着指向父节点的指针一直往上遍历,直到找到一个是它父节点的左子节点的节点;那这个父节点就是我们要找的目标节点 + + + +struct binaryTreeNode { + int val; + binaryTreeNode *left; + binaryTreeNode *right; + binaryTreeNode *parent; + +}; + + +binaryTreeNode* getNext(binaryTreeNode *pNode) +{ + if(pNode == nullptr) return nullptr; + + binaryTreeNode *pNext = nullptr; + + //存在右子树,则下一个节点是右子树的最左子节点 + if(pNode->right != nullptr) + { + binaryTreeNode *pRight = pNode->right; + while(pRight != nullptr) { + pRight = pRight->left; + } + + pNext = pRight; + + } + + //不存在右子树但是存在父节点(注意:只有根节点不存在父节点) + else if(pNode->parent != nullptr) + { + binaryTreeNode *pCurrent = pNode; + binaryTreeNode *pParent = pNode->parent; + + //不存在右子树并且该节点为父节点的右节点,则一直往上搜索 + while(pParent != nullptr && pCurrent == pParent->right) + { + pCurrent = pParent; + pParent = pParent->parent; + } + + pNext = pParent; + + } + + return pNext; +} + + + +TreeNode* getNextNode(TreeNode *node) +{ + if(node == nullptr) return nullptr; + + //存在右子树 + if(node->right) { + TreeNode *pNext = node->right; + while(pNext->left) { + pNext = pNext->left; + } + return pNext; + } + + if(node->parent) { + TreeNode *pParent = node->parent; + if(node == pParent->left) { //不存在右子树,且是父节点的左孩子 + return pParent; + } + else { //父节点的右孩子 + TreeNode *pCur = node; + while(parent && pCur == pParent->right) { //一直往上找到一个是父节点左孩子的节点 + pCur = pParent; + pParent = pParent->parent; + } + return pParent; + } + } + + //其他情况返回空指针 + return nullptr; +} + +struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode *parent; +}; + +TreeNode *GetNextNode(TreeNode *pNode) +{ + if(pNode == nullptr) return pNode; + + if(pNode->right) //存在右子树,则下一个节点为右子数的最左子节点 + { + TreeNode *pNext = pNode->right; + while(pNext->left) { + pNext = pNext->left; + } + + return pNext; + } + else if(pNode->parent) + { + //不存在右子树 + TreeNode *pParent = pNode->parent; + if(pNode == pParent->left) { //当前节点是父节点的左子节点,则下一个节点就是父节点 + return pParent; + } + + //当前节点是父节点的右子节点,则一直往上找到一颗节点为父节点的左子节点,则这个父节点就是下一个节点 + while(pParent && pNode == pParent->left) + { + pNode = pParent; + pParent = pParent->parent; + } + return pParent; + } + + //不存在右子树且不存在父节点,说明是根节点,直接返回nullptr + return nullptr; +} + diff --git "a/\345\211\221\346\214\207Offer/ex9.cc" "b/\345\211\221\346\214\207Offer/ex9.cc" new file mode 100755 index 0000000..3684cde --- /dev/null +++ "b/\345\211\221\346\214\207Offer/ex9.cc" @@ -0,0 +1,59 @@ + + +/* + 面试题9:利用两个栈来实现一个队列:实现其两个函数,在队列尾插入元素,在队首删除元素 +*/ + + +// 思路:定义两个栈stack1和stack2,stack1用来存放压入栈的数据 +//当队列插入数据时,直接将其压入栈1 +//当队列需要删除元素时,由于队列的先进先出的特点,先进去的元素都在栈1的 +//栈底,所以删除元素时先将栈1的所有元素弹出压入栈2,则先入队的元素就在 +//栈2的栈顶,再弹出栈2的栈顶元素即可完成队列的删除操作 +//总结起来删除操作过程为:判断栈2是否为空,若不为空,直接弹出栈2的栈顶元素 +//若栈2为空,将栈1的元素弹出逐个压入栈2再弹出栈2的栈顶元素即可 + + +template class CQueue{ + public: + CQueue(); + ~CQueue(); + + void appendTail(const T &node); + T deleteHead(); + + private: + stack stack1; + stack stack2; + +}; + + +template void CQueue::appendTail(const T &element){ + stack1.push(element); + +} + + +template T CQueue::deleteHead(){ + if(stack2.size() <= 0){ + while(stack1.size() > 0){ + T data = stack1.top(); + stack1.pop(); + stack2.push(data); + } + } + + // if(stack2.size() == 0) throw new execption("Queue is empty!"); //只有throw没有catch,也可写成下面这样的形式 + if(stack2.size() == 0){ //栈为空输出警告信息后直接退出程序 + std::cout << "Queue is Empty!" << std::endl; + exit(0); + } + + + T head = stack2.top(); + stack2.pop(); + + return head; + +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207Offer/test" "b/\345\211\221\346\214\207Offer/test" new file mode 100755 index 0000000..b4bcd1c Binary files /dev/null and "b/\345\211\221\346\214\207Offer/test" differ diff --git "a/\345\211\221\346\214\207Offer/test.cc" "b/\345\211\221\346\214\207Offer/test.cc" new file mode 100755 index 0000000..fa68d2b --- /dev/null +++ "b/\345\211\221\346\214\207Offer/test.cc" @@ -0,0 +1,75 @@ + + +#include +#include + +void deleteFitstFromSecond(char *pFirst, char *pSecond); +void deleteFitstFromSecond(std::string &first, std::string &second); +void test(std::string &str); + +int main() { + std::string str1 = "We are students", str2 = "aeiou"; + + deleteFitstFromSecond(str1, str2); + // test(str1); + std::cout << str1 << std::endl; + + return 0; +} + +void test(std::string &str) +{ + str[3] = '\0'; +} + + +//使用C语言编写 + +void deleteFitstFromSecond(char *pFirst, char *pSecond) +{ + if(pFirst == nullptr || pSecond == nullptr) return; + + std::vector count(26, 0); + while(*pSecond != '\0') { + count[*pSecond-'a']++; + pSecond++; + } + + int cur = 0; + char *p = pFirst; + while(*p != '\0') { + if(count[*p-'a']) { + p++; + } + else { + pFirst[cur++] = *p; + p++; + } + } + + pFirst[cur] = '\0'; + +} + + +void deleteFitstFromSecond(std::string &first, std::string &second) +{ + if(first.empty() || second.empty()) return; + + std::vector count(26, 0); + for(const char &c : second) { + count[c-'a']++; + } + + int cur = 0; + for(int i = 0; i < first.size(); i++) + { + if(count[first[i]-'a']) continue; + + first[cur++] = first[i]; + } + + // first[cur] = '\0'; //添加字符串结尾符号 + first = first.substr(0, cur); //不要犯上面这种低级错误,string中'\0'不能作为string类字符串的结尾 + +} \ No newline at end of file