-
gdb图形化调试
gdb是linux下很强大的调试工具,它使用命令行进行交互。相比于windows下visual studio的图形化调试界面,gdb的命令行方式操作起来不是很方便,从用户友好度上二者难以相提并论。不过gdb也有许多配套的前端组件,提供了图形化界面展示调试过程中的信息,这样就比传统命令行方式要方便很多。本文介绍了使用图形化的gdb前端让调试变得便捷高效,建议再阅读本文之前先掌握一些gdb的基础知识。
-
每周算法:下一个组合
leetcode算法题第31道,难度为medium。这道题考察题意理解的准确性和思路的全面性,对于题目所包含规律的总结也很重要。
-
每周算法:两整数相除
leetcode算法题第29道,难度为medium。从题目描述上来看,这道题考察两数相除的计算,貌似很简单,但如果仔细研究下来,就会发现这道题所考察的知识很综合。
-
在EMACS中对目录进行独立配置
如果你曾经同时维护多个软件项目,每个软件项目的代码风格都有各自的偏好。举个常见的例子,项目A要求使用
tab
进行缩进,而项目B要求使用空格进行缩进,虽然这样的代码风格问题看起来无关紧要,但这确实是代码编写中实实在在的问题。本文无意于讨论两者风格的优劣,而是想介绍在EMACS中优雅地解决这个问题的方法。 -
每周算法:删去有序数组中的重复元素
leetcode算法题第26道,难度为easy,这是非常基础的一道题。
-
每周算法:调换链表中节点
leetcode算法第24题,难度为medium。将链表中的节点成对翻转,考察链表结构的理解和节点的操作。
-
每周算法:生成有效的括号组合
leetcode 算法题第22道,难度为medium,对指定数量的括号进行排列组合,列举出其中有效的结果。对括号的处理通常出现在表达式分析中,这道题目是了解括号表达式特性的很好切入点。
-
路由、调制解调器和交换机
路由、调制解调器和交换机,这三个是我们经常使用的网络设备。它们在网络中的作用是什么?它们工作在网络模型的哪一层?本篇文章将带你了解他们的原理与和区别。
-
每周算法:删去单向链表倒数第n个节点
leetcode算法题第19道,难度为medium,考察链表的基本操作。
-
IP协议(RFC791)
本文是IPv4协议的摘要和笔记,IPv4协议格式由RFC791规定,RFC791协议的原文可以在 这里 找到。
-
网络通信协议
本文总结了两种常见的网络模型,OSI模型和TCP/IP模型,并比较了二者之间的区别。
-
每周算法:四数之和
Description
Given an array
nums
of n integers and an integertarget
, are there elements a, b, c, and d innums
such that a + b + c + d =target
? Find all unique quadruplets in the array which gives the sum oftarget
.Note:
The solution set must not contain duplicate quadruplets.Example:
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0. A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
Solution
Apporach 1 暴力解法
将所有的组合穷举出来,与目标进行逐一比对,将满足条件的组合收集起来,就能得到结果。需要注意的是去除结果中的重复项。
vector<vector<int>> fourSum(vector<int>& nums, int target) { set<vector<int>> ans; for (size_t i = 0; i < nums.size(); ++i) { for (size_t j=i+1; j < nums.size(); ++j) { for (size_t k=j+1; k < nums.size(); ++k) { for (size_t m=k+1; m < nums.size(); ++m) { if (nums[i] + nums[j] + nums[k] + nums[m] == target) { vector<int> t({nums[i], nums[j], nums[k], nums[m]}); sort(t.begin(), t.end()); ans.insert(t); } } } } } return vector<vector<int>>(ans.begin(), ans.end()); }
Approach 2 拓展3sum算法
这道题的与之前的 3 sum 十分类似,通过简单的拓展就能得到该问题的解法。
vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> ans; std::sort(nums.begin(), nums.end()); for (size_t i = 0; i < nums.size();) { int n1 = nums[i]; int target_1 = target - n1; for (size_t j=i+1; j<nums.size();) { int n2 = nums[j]; int target_2 = target_1 - n2; int front = j+1; int end = nums.size() - 1; while (front < end) { int n3 = nums[front]; int sum = n3 + nums[end]; if (sum == target_2) { ans.push_back(vector<int> ({n1, n2, n3, nums[end]})); do { ++front; } while(front < end && nums[front] == n3); } else if (sum > target_2) { --end; } else { ++front; } } do { ++j; } while (j<nums.size() && nums[j] == n2); } do { ++i; } while (i < nums.size() && nums[i] == n1); } return ans; }
Approach 3 优化的拓展3sum算法
在 approach 2 的基础上,增加一些边界条件判断,能够很大程度上提升算法的速度。下面的代码截取自leetcode,通过增加边界条件的判断,可以明显缩短代码的运行耗时。其中注释的代码是令一种较慢边界条件的判断方法,该代码的作者进一步优化了边界条件的判断逻辑。可以说,这种解法就是压榨算法的性能。这种优化方法是值得思考和学习的。
vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> res; if (nums.size() < 4) return res; sort(nums.begin(), nums.end()); int len = nums.size(); for (int i = 0; i < len-3; i++) { //avoid duplicate if (i > 0 && nums[i] == nums[i-1]) continue; // if (nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) break; // if (nums[i] + nums[len-3] + nums[len-2] + nums[len-1] < target) continue; //version3: less tight pruning if (4 * nums[i] > target) break; if (nums[i] + 3 * nums[len-1] < target) continue; for (int j = i+1; j < len-2; ++j) { if (j > i+1 && nums[j] == nums[j-1]) continue; // if (nums[i] + nums[j] + nums[j+1] + nums[j+2] > target) break; // if (nums[i] + nums[j] + nums[len-2] + nums[len-1] < target) continue; //version3: less tight pruning if (nums[i] + 3* nums[j] > target) break; if (nums[i] + nums[j] + 2 * nums[len-1] < target) continue; //now the problems becomes 3 sum problem and only two other elements only to be considered int left = j+1, right = len-1; int sofar = nums[i] + nums[j]; while (left < right) { if (sofar + nums[left] + nums[right] == target) { res.push_back(vector<int>({nums[i], nums[j], nums[left], nums[right]})); //how to skip the duplicate left and right //version1: my own version // left++; // right--; // while (left < right && nums[left-1] == nums[left]) ++left; // while (right > left && nums[right+1] == nums[right]) --right; //version2: refer others do{left++;} while (left < right && nums[left] == nums[left-1]); do{right--;} while (right > left && nums[right] == nums[right+1]); } else if (sofar + nums[left] + nums[right] < target) left++; else right--; } } } return res; }