This commit is contained in:
ranwenjie
2021-09-29 19:20:38 +08:00
parent fc99cdfa71
commit 0a43530e64
11 changed files with 187 additions and 58 deletions
+1 -1
View File
@@ -149,7 +149,7 @@
### 归并排序merge
分治算法,必然用到递归
分治算法(divide-and-conquer),必然用到递归 ;
2个有序数组的合并操作是O(n)的复杂度
因此我们可以将无序的数组,分成2个子数组分别排序,然后再merge,依次类推
+30 -3
View File
@@ -25,9 +25,9 @@ int binary_search(int *a,int length,int k){
int high = length-1;
int mid;
while(low<high){
while(low<high){//bug
mid = (low+high)/2;
if (a[mid] < k) low = mid+1;
if (a[mid] < k) low = mid+1; //不+1的话, 会有个bug: 可能 死循环
if (a[mid == k]) return mid;
if (a[mid] > k) high = mid-1;
}
@@ -39,16 +39,43 @@ int binary_search(int *a,int length,int k){
```
注意细节
mid+1/mid-1 , 否则的话,有可能死循环
while(low <= high) 而不是 while(low<high)
mid = (low+high)/2; 跟 mid = left + (right - left) / 2; 有什么区别?
```
如果搜索有序数列是 `[1,2,2,2,2,3]` 这种,想得到 target 的左侧边界,即索引 1,或者我想得到 target 的右侧边界,即索引 4 ; 这时候怎么处理呢?
你也许会说,找到一个 target,然后向左或向右线性搜索不行吗?可以,但是不好,因为这样难以保证二分查找对数级的复杂度了。
寻找左侧边界的二分搜索
```
int left_binary_search(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length; // 注意
while (left < right) { // 注意
int mid = left + (right - left) / 2;
if (nums[mid] == target) { //找到 target 时不要立即返回,而是缩小「搜索区间」的上界 right
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意 , 这里没有 -1
}
}
return left;
}
```
## 分块查找
+57
View File
@@ -10,6 +10,7 @@
> 自顶向下的递归,自底向上是迭代
## 斐波那契数列
fib(n)=fib(n-1)+fib(n-2)
@@ -67,6 +68,62 @@ int fib(int n) {
```
## 合并有序链表
递归解法
public static LinkedNode mergeSeqLink2(LinkedNode l1, LinkedNode l2){
if(l1 == null){
return l2;
}
if(l2 == null){
return l1;
}
if(l1.value < l2.value){
l1.next = mergeSeqLink2(l1.next,l2);
return l1;
}else{
l2.next = mergeSeqLink2(l2.next,l1);
return l2;
}
}
```
非递归解法
```
public static LinkedNode mergeSeqLink(LinkedNode l1, LinkedNode l2){
if (l1 == null) return l2;
if (l2 == null) return l1;
LinkedNode result = new LinkedNode(0);
LinkedNode tmp = result;
while (l1 != null && l2 != null) {
if (l1.value < l2.value) {
tmp.next = l1;
tmp = tmp.next; //tmp 指针前进
l1 = l1.next ; //l1 前进
} else {
tmp.next = l2;
l2 = l2.next;
tmp = tmp.next;
}
}
if (l1 != null) {
tmp.next = l1;
}
if (l2 != null) {
tmp.next = l2;
}
return result.next;
}
```
@@ -30,14 +30,18 @@ struct ListNode
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// p1 指向 A 链表头结点,p2 指向 B 链表头结点
ListNode p1 = headA, p2 = headB;
while (p1 != p2) {
// p1 走一步,如果走到 A 链表末尾,转到 B 链表
if (p1 == null) p1 = headB;
else p1 = p1.next;
// p2 走一步,如果走到 B 链表末尾,转到 A 链表
if (p2 == null) p2 = headA;
else p2 = p2.next;
}
return p1;
}
```
@@ -1,6 +1,50 @@
#数列-nsum问题
## 数组,找出和为 s 的两个数
暴力解法
```
class Solution {
public int[] twoSum(int[] nums, int target) {
int res[] = new int[2];
for(int i = 0; i < nums.length; i++){
for(int j = i + 1; j < nums.length; j++){
if(nums[i] + nums[j] == target){
res[0] = i;
res[1] = j;
break;
}
}
}
return res;
}
}
```
使用 hash表,2遍扫描
``` Java
class Solution {
public int[] twoSum(int[] nums, int target) {
int res[] = new int[2];
Map<Integer, Integer> map= new HashMap<>();
for(int i = 0; i < nums.length; i++){
map.put(nums[i], i);
}
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i];
if(map.containsKey(temp) && map.get(temp) != i){
res[0] = map.get(temp);
res[1] = i;
}
}
return res;
}
}
```
## 找出和为N+1的2个数
+44 -43
View File
@@ -3,49 +3,6 @@
矩阵在计算机中表示就是二维数组。这部分内容都是有关二维数组和矩阵相关的题目。
## 二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
```
1 3 5 7
2 5 7 12
4 6 9 23
6 9 23 75
```
```
int exist_inmatrix(int *matrix,int rows,int cols,int target);
```
## 矩阵中最大的二维矩阵
求一个矩阵中最大的二维矩阵(元素和最大).如:
```
1 2 0 3 4
2 3 4 5 1
1 1 5 3 0
```
中最大的是:
```
4 5
5 3
```
要求:
(1)写出算法;
(2)分析时间复杂度;
(3)用C写出关键代码
```
int max_sum_submatrix(int *matrix,int rows,int cols,int *tmatrix,int *trows,int tcols)
```
## 顺时针打印矩阵
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
@@ -60,6 +17,7 @@ int max_sum_submatrix(int *matrix,int rows,int cols,int *tmatrix,int *trows,int
则依次打印出数字`1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10` 。
分析:包括Autodesk、EMC在内的多家公司在面试或者笔试里采用过这道题。
难点: 各种边界条件判断,很容易搞错
一圈一圈打印,第一圈origin是(0,0),第二圈是(1,1)
@@ -164,6 +122,49 @@ void printArry(int *a,int rows,int columns)
## 二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
```
1 3 5 7
2 5 7 12
4 6 9 23
6 9 23 75
```
```
int exist_inmatrix(int *matrix,int rows,int cols,int target);
```
## 矩阵中最大的二维矩阵
求一个矩阵中最大的二维矩阵(元素和最大).如:
```
1 2 0 3 4
2 3 4 5 1
1 1 5 3 0
```
中最大的是:
```
4 5
5 3
```
要求:
(1)写出算法;
(2)分析时间复杂度;
(3)用C写出关键代码
```
int max_sum_submatrix(int *matrix,int rows,int cols,int *tmatrix,int *trows,int tcols)
```
## 矩阵中的最大上升路径
@@ -118,7 +118,7 @@ d=100时,h差不多3个
沿着搜索的路径从root一直到叶节点
每个节点的关键字个数在【d-1,2d-1】之间,当节点的关键字个数是2t-1时,再加入target就违反了B树定义,需要对该节点进行分裂:已中间节点为界,分成2个包含d-1个关键字的子节点(另外还有一个分界关键字,2*(d-1)+1=2d-1),同时把该分界关键字提升到该叶子的父节点中,如果这导致父节点关键字个数超过2d-1,就继续向上分裂,直到根节点。
每个节点的关键字个数在【d-1,2d-1】之间,当节点的关键字个数是2t-1时,再加入target就违反了B树定义,需要对该节点进行分裂:已中间节点为界,分成2个包含 `d-1` 个关键字的子节点(另外还有一个分界关键字,`2*(d-1)+1=2d-1)`,同时把该分界关键字提升到该叶子的父节点中,如果这导致父节点关键字个数超过 `2d-1`, 就继续向上分裂,直到根节点。
如下演示动画,往度d=2的B树中插入:` 6 10 4 14 5 11 15 3 2 12 1 7 8 8 6 3 6 21 5 15 15 6 32 23 45 65 7 8 6 5 4`
+1 -2
View File
@@ -1,5 +1,4 @@
## 海量数据处理
# 海量数据处理
所谓海量数据,就是数据量太大,要么在短时间内无法计算出结果,要么数据太大,无法一次性装入内存。
@@ -1,5 +1,4 @@
## Hash映射,分而治之
# Hash映射,分而治之
这里的`Hash映射`是指通过一种映射散列的方式,将海量数据均匀分布在对应的内存或更小的文件中
@@ -1,10 +1,9 @@
### 分布处理之Mapreduce
# 分布处理之MapReduce
MapReduce是Google提出的一个软件架构,用于大规模数据集(大于1TB)的并行运算。概念“Map(映射)”和“Reduce(归纳)”,及他们的主要思想,都是从函数式编程语言借来的,还有从矢量编程语言借来的特性。MapReduce的伟大之处就在于让不熟悉并行编程的程序员也能充分发挥分布式系统的威力。
##### Mapreduce工作原理
### Mapreduce工作原理
举一个例子:10年内所有论文(当然有很多很多篇)里面出现最多的几个单词。
@@ -18,7 +17,7 @@ map函数和reduce函数是交给用户实现的,这两个函数定义了任
##### Hadoop
### Hadoop
谷歌技术有"三宝",GFS、MapReduce和大表(BigTable)。
@@ -1,2 +1 @@
## simhash算法
# simhash算法