记录算法基础题思路:
step1
插入位置查找: https://leetcode-cn.com/problems/search-insert-position/submissions/
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例:
输入: [1,3,5,6], 5
输出: 2
int searchInsert(vector& nums, int target) {
/* 二分查找方法改造, 适用不存在场景 */
/* 1 左插入场景:假设target < nums[mid] 但 > nums[mid - 1](边界0), 在mid插入 */
/* 2 右插入场景:假设target > nums[mid] 但 < nums[mid + 1](边界size - 1), 在mid + 1 插入 */
int begin = 0;
int end = nums.size() - 1;
while (begin <= end) {
int mid = (end + begin) / 2;
if (target == nums[mid]) {
return mid;
} else if (target < nums[mid]) {
if ((mid == 0) || target > nums[mid - 1]) {
return mid;
}
end = mid - 1;
} else {
if ((mid == nums.size() - 1) || target < nums[mid + 1]) {
return mid + 1;
}
begin = mid + 1;
}
}
return 0; /* 实际不会进来 */
}
区间查找:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/submissions/
给定一个按照升序排列的整数数组 nums,和一个目标值target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
public:
vector searchRange(vector& nums, int target) {
/* 基于二分查找做区间改造,做二次查找分别找左右端点 */
/* target == nums[mid] && target > nums[mid - 1] 左端点, 边界0*/
/* target == nums[mid] && target < nums[mid + 1] 左端点, 边界size -1 */
vector res;
res.push_back(find_left_pos(nums, target));
res.push_back(find_right_pos(nums, target));
return res;
}
private:
int find_left_pos(vector& nums, int target) {
int begin = 0;
int end = nums.size() - 1;
while (begin <= end) {
int mid = (end + begin) / 2;
if (target == nums[mid]) {
if (mid == 0 || nums[mid - 1] < target) {
return mid;
}
end = mid - 1;
} else if (target < nums[mid]) {
end = mid - 1;
} else if (target > nums[mid]) {
begin = mid + 1;
}
}
return -1;
}
int find_right_pos(vector& nums, int target) {
int begin = 0;
int end = nums.size() - 1;
while (begin <= end) {
int mid = (end + begin) / 2;
if (target == nums[mid]) {
if ((mid == nums.size() - 1) || nums[mid + 1] > target) {
return mid;
}
begin = mid + 1;
} else if (target < nums[mid]) {
end = mid - 1;
} else if (target > nums[mid]) {
begin = mid + 1;
}
}
return -1;
}
旋转数组查找:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/submissions/
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
int search(vector& nums, int target) {
/* 二分查找改进补充落在旋转区间方式, 如nums[begin]>nums[end]为旋转区间,否则为递增区间*/
int begin = 0;
int end = nums.size() - 1;
while (begin <= end) {
int mid = (end + begin) / 2;
if (target == nums[mid]) {
return mid;
} else if (target < nums[mid]) {
/* 如果begin到mid为递增区间, mid到end为旋转区间*/
if (nums[begin] < nums[mid]) {
if (target >= nums[begin]) { // 递增区间有
//end = mid - 1; //递增区间有(优化为下面一句, 避免反复空间判断)
return normal_binary_search(nums, begin, mid - 1, target);
} else { //递增区间没有,在旋转区间找
begin = mid + 1;
}
/* 如果begin到mid为旋转区间,mid到end为递增区间 */
} else if (nums[begin] > nums[mid]) {
end = mid - 1; // 递增区间没,在旋转区间找
} else { //nums[begin] == nums[mid],mid和begin值相同
begin = mid + 1;
}
} else if (target > nums[mid]) {
/* 如果begin到mid为递增区间, mid到end为旋转区间*/
if (nums[begin] < nums[mid]) {
begin = mid + 1; //递增区间没有,在旋转区间找
/* 如果begin到mid为旋转区间,mid到end为递增区间 */
} else if (nums[begin] > nums[mid]) {
if (target <= nums[end]) {
//begin = mid + 1; //递增区间有(优化为下面一句, 避免反复空间判断)
return normal_binary_search(nums, mid + 1, end, target);
} else {
end = mid - 1; // 递增区间没有,在旋转区间找
}
} else { //nums[begin] == nums[mid],mid和begin值相同
begin = mid + 1;
}
}
}
return -1;
}
二叉查找树编码解码:https://leetcode-cn.com/problems/serialize-and-deserialize-bst/submissions/
序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。
设计一个算法来序列化和反序列化二叉搜索树。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。
编码的字符串应尽可能紧凑。
public:
// Encodes a tree to a single string.
/* 对查找二叉树进行前序遍历,将遍历到的结果按顺序插入能得到相同的查找二叉树 */
string serialize(TreeNode* root) {
string res;
bst_preorder(root, res);
return res;
}
void bst_preorder(TreeNode* root, string &res) {
if (root == NULL) {
return;
}
int val = root->val;
/* 前序遍历,注意把字符串反序,取值反算得到val更简单, 用#分割数据 */
string tmp;
while (val != 0) {
tmp += val % 10 + '0';
val /= 10;
}
for (int i = tmp.size() - 1; i >= 0; i--) {
res += tmp[i];
}
res += '#';
bst_preorder(root->left, res);
bst_preorder(root->right, res);
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if (data.size() == 0) {
return NULL;
}
vector node_vec;
int val = 0;
for (int i = 0; i < data.size(); i++) {
if (data[i] == '#') {
node_vec.push_back(new TreeNode(val));
val = 0;
} else {
val = val * 10 + data[i] - '0';
}
}
for (int i = 1; i < node_vec.size(); i++) {
bst_insert(node_vec[0], node_vec[i]);
}
return node_vec[0];
}
void bst_insert(TreeNode* root, TreeNode* node) {
if (node->val < root->val) {
if (root->left == NULL) {
root->left = node;
} else {
bst_insert(root->left, node);
}
} else {
if (root->right == NULL) {
root->right = node;
} else {
bst_insert(root->right, node);
}
}
}
逆序数:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/submissions/
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例:
输入: [5,2,6,1]
输出: [2,1,1,0]
struct BstNode {
int val;
int count; //左子数中节点个数
BstNode *left;
BstNode *right;
BstNode(int x) : val(x), left(NULL), right(NULL), count(0) {}
};
vector countSmaller(vector& nums) {
/* 利用查找二叉树数据结构,逆序插入数组nums[i], 插入过程生成节点的count[i]
每个节点加入一个count来记录其左子树节点的个数,插入过程如果插入左子树就更新count,
如果插入右子树,count[i] += node->count + 1(当前节点左子树数量+1); */
vector count;
vector res;
if (nums.size() == 0) {
return res;
}
BstNode *root = new BstNode(nums[nums.size() - 1]);
count.push_back(0);
for (int i = nums.size() - 2; i >= 0; i--) {
int small_count = 0;
bst_insert(root, new BstNode(nums[i]), small_count);
count.push_back(small_count);
}
for (int i = count.size() - 1; i >= 0; i--) {
res.push_back(count[i]);
}
return res;
}
private:
void bst_insert(BstNode* root, BstNode* node, int &small_count) {
if (node->val <= root->val) {
root->count++;//往左子树插入,更新count
if (root->left == NULL) {
root->left = node;
} else {
bst_insert(root->left, node, small_count);
}
} else {
small_count += root->count + 1;//往右子树插入,更新统计small_count
if (root->right == NULL) {
root->right = node;
} else {
bst_insert(root->right, node, small_count);
}
}
}