diff --git a/archives/2024/01/index.html b/archives/2024/01/index.html index a1aa16236..751a3c3b9 100644 --- a/archives/2024/01/index.html +++ b/archives/2024/01/index.html @@ -305,8 +305,8 @@

thinklive

-
@@ -325,8 +325,8 @@

thinklive

-
@@ -385,8 +385,8 @@

thinklive

-
@@ -405,8 +405,8 @@

thinklive

-
@@ -425,8 +425,8 @@

thinklive

-
@@ -445,8 +445,8 @@

thinklive

-
diff --git a/archives/2024/01/page/2/index.html b/archives/2024/01/page/2/index.html index 066d64682..819a6b1a7 100644 --- a/archives/2024/01/page/2/index.html +++ b/archives/2024/01/page/2/index.html @@ -265,8 +265,8 @@

thinklive

-
@@ -385,8 +385,8 @@

thinklive

-
@@ -405,8 +405,8 @@

thinklive

-
@@ -425,8 +425,8 @@

thinklive

-
@@ -445,8 +445,8 @@

thinklive

-
diff --git a/archives/2024/06/index.html b/archives/2024/06/index.html index 399664005..1b318b4fd 100644 --- a/archives/2024/06/index.html +++ b/archives/2024/06/index.html @@ -265,7 +265,7 @@

thinklive

-
diff --git a/archives/2024/index.html b/archives/2024/index.html index 56f7fc0e1..2a486536a 100644 --- a/archives/2024/index.html +++ b/archives/2024/index.html @@ -265,7 +265,7 @@

thinklive

-
@@ -365,8 +365,8 @@

thinklive

-
@@ -385,8 +385,8 @@

thinklive

-
@@ -445,8 +445,8 @@

thinklive

-
diff --git a/archives/2024/page/2/index.html b/archives/2024/page/2/index.html index dff1f54d6..5df270015 100644 --- a/archives/2024/page/2/index.html +++ b/archives/2024/page/2/index.html @@ -265,8 +265,8 @@

thinklive

-
@@ -285,8 +285,8 @@

thinklive

-
@@ -305,8 +305,8 @@

thinklive

-
@@ -325,8 +325,8 @@

thinklive

-
@@ -445,8 +445,8 @@

thinklive

-
diff --git a/archives/2024/page/3/index.html b/archives/2024/page/3/index.html index c4c1f5e60..0c541ef80 100644 --- a/archives/2024/page/3/index.html +++ b/archives/2024/page/3/index.html @@ -265,8 +265,8 @@

thinklive

-
@@ -285,8 +285,8 @@

thinklive

-
@@ -305,8 +305,8 @@

thinklive

-
diff --git a/archives/index.html b/archives/index.html index 0932515c9..861eee06e 100644 --- a/archives/index.html +++ b/archives/index.html @@ -265,7 +265,7 @@

thinklive

-
@@ -365,8 +365,8 @@

thinklive

-
@@ -385,8 +385,8 @@

thinklive

-
@@ -445,8 +445,8 @@

thinklive

-
diff --git a/archives/page/2/index.html b/archives/page/2/index.html index fe11f0918..98e1f5442 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -265,8 +265,8 @@

thinklive

-
@@ -285,8 +285,8 @@

thinklive

-
@@ -305,8 +305,8 @@

thinklive

-
@@ -325,8 +325,8 @@

thinklive

-
@@ -445,8 +445,8 @@

thinklive

-
diff --git a/archives/page/3/index.html b/archives/page/3/index.html index db107451e..ecef1e1f6 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -265,8 +265,8 @@

thinklive

-
@@ -285,8 +285,8 @@

thinklive

-
@@ -305,8 +305,8 @@

thinklive

-
diff --git a/atom.xml b/atom.xml index e2ec5fb13..a3944b1d3 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2024-06-18T13:40:33.278Z + 2024-06-18T13:45:50.778Z https://thinklive1.github.io/ @@ -18,12 +18,12 @@ 暑期复习日活 - - https://thinklive1.github.io/thinklive/26286/ + + https://thinklive1.github.io/thinklive/54551/ 2024-06-17T08:27:18.764Z - 2024-06-18T13:40:33.278Z + 2024-06-18T13:45:50.778Z - 删除线表示完成,未完成日后补上视为完成

2024/6/17
单词200次
操作系统二轮复习——80%
计算机网络二轮复习——20%
英语真题训练

2024/6/18
单词200次 李永乐线代——矩阵部分例题50%
英语真题训练

2024/6/19(完成课程作业因此工作量减半)
单词200次
操作系统二轮复习——100%~~
李永乐线代——矩阵部分例题75%~~

]]>
+ 删除线表示完成,未完成日后补上视为完成

2024/6/17
单词200次
操作系统二轮复习——80%
计算机网络二轮复习——20%
英语真题训练

2024/6/18
单词200次 李永乐线代——矩阵部分例题50%
英语真题训练

2024/6/19(完成课程作业因此工作量减半)
单词200次
操作系统二轮复习——100%~~
李永乐线代——矩阵部分例题75%~~

2024/6/20 单词150次
计算机网络二轮复习——40%~~
李永乐线代——矩阵部分例题100%~~
李永乐线代——矩阵部分练习题100%~~
英语真题训练~~

]]>
<p><del>删除线</del>表示完成,未完成日后补上视为完成</p> @@ -38,7 +38,12 @@ <p>2024/6/19(完成课程作业因此工作量减半)<br /> 单词200次<br /> 操作系统二轮复习——100%~~<br /> -李永乐线代——矩阵部分例题75%~~<br /> +李永乐线代——矩阵部分例题75%~~</p> +<p>2024/6/20 单词150次<br /> +计算机网络二轮复习——40%~~<br /> +李永乐线代——矩阵部分例题100%~~<br /> +李永乐线代——矩阵部分练习题100%~~<br /> +英语真题训练~~</p> @@ -1043,17 +1048,18 @@ A.L.I.C.E(原曲:不可思议之国的爱丽丝)<br />
- 基于斯坦福cs106b的c++数据结构笔记 - - https://thinklive1.github.io/thinklive/16615/ + 基于斯坦福cs106l的c++编程规范笔记 + + https://thinklive1.github.io/thinklive/48468/ 2024-01-20T11:53:48.573Z 2023-11-27T12:47:59.687Z - 一些查找和排序算法

二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

容器类

set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

哈希表

哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

检查表中是否存在元素

● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

将元素插入表中

● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

从表中删除一个元素

● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

“罗宾汉哈希表”

  • 如果插入的值比其将插入的位置的值距离索引更远,则替换插入值和当前值
  • 删除值时,将后其离原键远的元素前移
  • ★ 罗宾汉哈希一览 ★
  • 检查表中是否存在元素:
  • ● 跳转到表中由元素的散列码给出的位置。
  • ● 向前扫描——如有必要环绕——记录有多少步 你拿走了。 当您找到该项目、找到一个空白槽或找到一个 离家更近的空位比你走的步数还多。
  • 将元素插入表中:
  • ● 如果该元素已在表中,则什么也不做。
  • ● 跳转到由元素的散列码给出的表槽。 向前扫描 - 换行 如有必要,四处走走——记录所走的步数。 如果你找到一个 空插槽,将元素放在那里。 否则,如果当前插槽已满并且 比您插入的元素更靠近家,将要插入的项目放在那里, 替换那个位置的元素,然后继续插入,就好像你 正在插入被置换的元素。
  • 从表中删除一个元素:
  • ● 跳转到由元素的散列码给定的槽。
  • ● 向前走——如有必要,环绕——直到物品或空槽被放置 成立。 如果找到该项目,请将其删除。 然后,继续前进——包裹 around as necessary – 将表中的元素向后移动一个槽位,直到 找到空插槽或位于其原始位置的项目

string类

str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// count is npos, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

// both pos and pos+count are within bounds, returns [pos, pos+count)
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

// pos is within bounds, pos+count is not, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
// this is effectively equivalent to
// std::string sub4 = a.substr(17, 3);
// since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

try {
// pos is out of bounds, throws
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
} catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
}
}
输出:
abcdefghij
567
hij
pos exceeds string size

`replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

一些实现

优先队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include "HeapPQueue.h"
using namespace std;

HeapPQueue::HeapPQueue() {
elems = new DataPoint[INITIAL_SIZE] {};
for (int i=0;i<INITIAL_SIZE;i++)
{
elems[i].weight=0;
}
allocatedSize=INITIAL_SIZE;
}

HeapPQueue::~HeapPQueue() {
delete [] elems;
}

int HeapPQueue::size() const {
return logicalSize;
}

bool HeapPQueue::isEmpty() const {
return logicalSize==0;
}

void HeapPQueue::enqueue(const DataPoint& data) {
if (logicalSize+1<allocatedSize)
{
if (logicalSize==0)
{
elems[1]=data;
logicalSize++;
}
else
{
logicalSize++;
int i=1;
while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
{
i++;
}
if (i<logicalSize)
{
DataPoint temp=elems[i];
elems[i]=data;
for(i;i<logicalSize;i++)
{
DataPoint temp_plus=elems[i+1];
elems[i+1]=temp;
temp=temp_plus;

}
}
else
{
elems[i]=data;
}

}
}
}

DataPoint HeapPQueue::peek() const {
return elems[logicalSize];
}

DataPoint HeapPQueue::dequeue() {
DataPoint to_return=elems[1];
if(!isEmpty())
{

for (int i=1;i<logicalSize;i++)
{
elems[i]=elems[i+1];
}
elems[logicalSize]={};
logicalSize--;
}
return to_return;
}

计数排序

首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Given a Vector<int>, returns the largest number in that Vector. */
int maxOf(const Vector<int>& values) {
/* Bounds-check inputs. */
if (values.isEmpty()) {
error("Can't find the maximum of no values.");
}

int result = values[0];
for (int i = 1; i < values.size(); i++) {
result = max(result, values[i]);
}
return result;
}

/* Given a list of numbers, creates a histogram from those numbers. */
Vector<int> histogramFor(const Vector<int>& values) {
/* Create a histogram with the right number of slots. Initially, all values
* in the histogram will be zero.
*/
Vector<int> histogram(maxOf(values) + 1);

/* Scan across the input vector, incrementing the histogram values. */
for (int value: values) {
histogram[value]++;
}

return histogram;
}

void countingSort(Vector<int>& values) {
/* Edge Case: If the array is empty, then it's already sorted. This is
* needed because we can't take the maximum value of an empty vector.
*/
if (values.isEmpty()) {
return;
}

/* Form the histogram. */
auto histogram = histogramFor(values);

/* Scan across the histogram writing out the appropriate number of copies
* of each value. We track the index of the next free spot to write to,
* as it varies based on how many items we've written out so far.
*/
int next = 0;
for (int value = 0; value < histogram.size(); value++) {
/* Write out the right number of copies. */
for (int copy = 0; copy < histogram[value]; copy++) {
values[next] = value;
next++;
}
}
}

错题集

递归的效率优化

每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

递归计算给定元素的不同结构哈夫曼树的数量

对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numBSTsOfSize(int n) {

/* Base case: There’s only one tree of size 0, namely, the empty BST. */
if (n == 0) return 1;

/* Recursive case: Imagine all possible ways to choose a root and build the
* left and right subtrees.
*/
int result = 0;

/* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
for (int i = 0; i < n; i++) {
/* Each combination of a BST of i elements and a BST of n - 1 - i elements
* can be used to build one BST of n elements. The number of pairs of
* trees we can make this way is given by the product of the number of
* trees of each type.
*/
result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
}

return result;
}

递归解决吃巧克力问题

求出吃法数量

1
2
3
4
5
6
7
8
9
10
11
12
if (numSquares<0)
{
error("输入数据不能为负数");
}
else if (numSquares<=1)
{
return 1;
}
else
{
return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
}

打印每种吃法

`需要一个辅助向量储存历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Print all ways to eat numSquares more squares, given that we've
* already taken the bites given in soFar.
*/
void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
/* Base Case: If there are no squares left, the only option is to use
* the bites we've taken already in soFar.
*/
if (numSquares == 0) {
cout << soFar << endl;
}
/* Base Case: If there is one square lfet, the only option is to eat
* that square.
*/
else if (numSquares == 1) {
cout << soFar + 1 << endl;
}
/* Otherwise, we take take bites of size one or of size two. */
else {
printWaysToEatRec(numSquares - 1, soFar + 1);
printWaysToEatRec(numSquares - 2, soFar + 2);
}
}

void printWaysToEat(int numSquares) {
if (numSquares < 0) {
error("You owe me some chocolate!");
}

/* We begin without having made any bites. */
printWaysToEatRec(numSquares, {});
}

递归解决翻煎饼问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
bool isSorted(Stack<double> pancakes) {
double last = -1; // No pancakes have negative size;

while (!pancakes.isEmpty()) {
/* Check the next pancake. */
double next = pancakes.pop();
if (next < last) {
return false;
}

last = next;
}

/* Pancakes are in increasing order! */
return true;
}

/* Given a stack of pancakes and a flip size, flips that many pancakes
* on the top of the stack.
*/
Stack<double> flip(Stack<double> pancakes, int numToFlip) {
/* Take the top pancakes off the stack and run them into a queue.
* This preserves the order in which they were removed.
*/
Queue<double> buffer;
for (int i = 0; i < numToFlip; i++) {
buffer.enqueue(pancakes.pop());
}

/* Move the pancakes back. */
while (!buffer.isEmpty()) {
pancakes.push(buffer.dequeue());
}

return pancakes;
}

Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
/* Base Case: If the stack is sorted, great! We're done, and no flips
* were needed.
*/
if (isSorted(pancakes)) {
return { }; // No flips
}
/* Base Case: If the stack isn't sorted and we're out of flips, then
* there is no way to sort things.
*/
else if (numFlips == 0) {
return Nothing;
}
/* Recursive Case: The stack isn't sorted and we still have flips left.
* The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
* Try each option and see whether any of them work.
*/
for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
/* Make the flip and see if it works. */
auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
if (result != Nothing) {
/* The result holds all the remaining flips but doesn't know about
* the flip we just did. Insert that flip at the beginning.
*/
result.value().insert(0, numToFlip);
return result;
}
}

/* If we're here, then no matter which flip we make first, we cannot
* get the pancakes sorted. Give up.
*/
return Nothing;
}

递归解决天平问题

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
if (index == weights.size()) {
return amount == 0;
} else {
return isMeasurableRec(amount, weights, index + 1) ||
isMeasurableRec(amount + weights[index], weights, index + 1) ||
isMeasurableRec(amount - weights[index], weights, index + 1);
}
}

bool isMeasurable(int amount, const Vector<int>& weights) {
return isMeasurableRec(amount, weights, 0);
}

想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

  • 向左走,使规模上的净不平衡 n + w ,或
  • 向右走,使规模上的净不平衡 n – w ,或
  • 根本不习惯,留下净不平衡 n

如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

递归解决找零问题

不使用记忆的情况

`从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}
/* Base case: You need no coins to give change for no cents. */
else if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (coins.isEmpty()) {
return cents + 1;
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;
/* Pick a coin. */
int coin = coins.first();
/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
coins - coin);
/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}
/* Return whatever worked best. */
return bestSoFar;
}
}

使用记忆进行优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* How few coins are needed to make the total, given that we can only use
* coins from index startIndex and onward?
*/
int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
/* Base case: You need no coins to give change for no cents. */
if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (startIndex == coins.size()) {
return cents + 1;
}
/* Base case: We already know the answer. */
else if (memo[cents][startIndex] != -1) {
return memo[cents][startIndex];
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;

/* Pick a coin. */
int coin = coins[startIndex];

/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
coins, startIndex + 1,
memo);

/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}

/* Return whatever worked best. */
memo[cents][startIndex] = bestSoFar;
return bestSoFar;
}
}

int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}

/* Convert from a Set<int> to a Vector<int> so we have a nice ordering
* on things.
*/
Vector<int> coinVec;
for (int coin: coins) {
coinVec += coin;
}

/* Build our memoization table. Since the number of cents left ranges from
* 0 to cents, we need cents+1 rows. Since the start index of the coin
* ranges from 0 to coins.size(), we make coins.size() + 1 columns.
*
* -1 is used as a sentinel to indicate "nothing has been computed here
* yet."
*/
Grid<int> memo(cents + 1, coins.size() + 1, -1);

/* Now ask how many coins are needed to make the total, using any coins
* from index 0 onward.
*/
return fewestCoinsRec(cents, coinVec, 0, memo);
}

递归穷举付账单

递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
/* Base case: if there's one person left, they have to pay the whole bill. */
if (people.size() == 1) {
Map<string, int> finalPayments = payments;
finalPayments[people.first()] = total;
cout << finalPayments << endl;
}
/* Recursive case: The first person has to pay some amount between 0 and the
* total amount. Try all of those possibilities.
*/
else {
for (int payment = 0; payment <= total; payment++) {
/* Create a new assignment of people to payments in which this first
* person pays this amount.
*/
Map<string, int> updatedPayments = payments;
updatedPayments[people.first()] = payment;
listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
}
}
}
void listPossiblePayments(int total, const Set<string>& people) {
/* Edge cases: we can't pay a negative total, and there must be at least one
* person.
*/
if (total < 0) error("Guess you're an employee?");
if (people.isEmpty()) error("Dine and dash?");
listPossiblePaymentsRec(total, people, {});
}

递归寻找完全平方数列

主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Optional<Vector<int>> findSquareSequence(int n) {
/*Validate input.*/
if (n < 0) {
error("Don't be so negative!");
}

/* Build a set of the numbers 1, 2, 3, ..., n. */
Set<int> options;
for (int i = 1; i <= n; i++) {
options += i;
}
return findSequenceRec(options, { });
}

Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
const Vector<int>& soFar) {
/*Base Case: If all numbers are used, we have our sequence!*/
if (unused.isEmpty()) {
return soFar;
}

/* Recursive Case: Some number comes next. Try each of them and see which
* one we should pick.
*/
for (int next: unused) {
/* We can use this if either
*
* 1. the sequence is empty, so we're first in line, or
* 2. the sequence is not empty, but we sum to a perfect square
* with the previous term.
*/
if (soFar.isEmpty() ||
isPerfectSquare(next + soFar[soFar.size() - 1])) {
/* See what happens if we extend with this number. */
auto result = findSequenceRec(unused - next, soFar + next);
if (result != Nothing) {
return result;
}
}
}

/* Tried all options and none of them worked. Oh well! */
return Nothing;
}

汉诺塔递归

假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

1
2
3
4
5
6
7
8
9
10
11
int moveTower(int numDisks, char start, char finish, char temp) {
if (numDisks == 0) {
return 0;
} else {
int movesOne = moveTower(numDisks - 1, start, temp, finish);
moveSingleDisk(start, finish);
int movesTwo = moveTower(numDisks - 1, temp, finish, start);

return 1 + movesOne + movesTwo;
}
}
]]>
+ c++特性
  • 更好的C C++支持命令式编程,一种编程风格,其中程序按顺序执行的命令序列。从这个意义上讲,C++ 可以看作是对C 编程语言,使日常命令式编程更加直观和更容易使用。课程阅读器的这一部分介绍了一些 C++ 最常用的库,包括标准模板库,并展示了如何使用这些库来构建命令程式。 此外,它探索了最初出现在 C++ 语言中的新原语。C 编程语言,即指针、C 字符串和预处理器。
  • 数据抽象

C++与其兄弟C的最大区别在于_数据抽象_,程序执行的方式可以与程序执行的方式分开 程序员谈论那个程序。

  • 面向对象编程

. 面向对象编程是一种完全不同的方式考虑程序设计,可以极大地简化复杂的软件系统。 钥匙 面向对象背后的概念很简单,但要真正体会到面向对象的力量 编程,您将需要一次又一次地看到它的运行情况。 这部分课程 读者探索了面向对象编程中的主要概念以及如何在 C++ 中实现它继承和多态。

  • 泛型编程

泛型编程是一种编程风格,旨在构建可以解决一系列远远超出最初设想的问题的软件
履行。 虽然泛型编程的完整处理远远超出了介绍性的范围C++ 编程课,泛型编程的许多思想都可以访问并且可以从根本上改变了您对 C++ 编程的看法。

const

Can’t declare non-const reference to const variable Can’t declare non-const reference to const vari

图片 图片

模板

图片 函数指针:将函数作为对象传递

stl

sequence:线性,有顺序 associative:不一定线性,有索引机制(map)

vector:有顺序的相同类型的数据集合,大小可控制 ---子属性:size:元素数量 ---capacity:单个元素大小 图片 vector最常用,deque用于首部插入场合,list用于多种列表

associative(关联数组):有顺序的需要有比较方法,无序的需要哈希函数(更快) iterators(迭代器):用于访问容器中的所有数据 --常用函数,begin(),end(),iter++,*(pointer),== !=,=(赋值,复制), 图片 图片 图片

输入输出流

First call to std::cin >> creates a command line
prompt that allows the user to type until they hit enter

  • Each >> ONLY reads until the next whitespace
  • Whitespace = tab, space, newline
  • Everything after the first whitespace gets saved and
    used the next time std::cin >> is called
  • The place its saved is called a buffer 图片 图片 图片 图片 图片 图片 图片

hashmap的c++实现

相关函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
构造函数HashMap():
接受参数count(值的个数),hash function(有默认值)

参数(typename fitst,typename last,bucket_count,H)
//用一个容器首尾指针初始化hashmap
eg.
hashmap<k,m> map{vec.begin(),vec.end()}

参数(init_list init,bucket_count,H)
//用容器直接初始化hashmap
eg.
HashMap<char, int> map{{'a', 3}, {'b', 5}, {'c', 7}};

public:
key-键
mapped-被加密的值(int)
H-哈希函数
bucket_count(存储的键值对数组容量)
load_factor(内联函数,返回size/bucket_count,即实际储存值的键值对)
contains(参数const K& key判断是否存在改键,返回bool值)
at(参数k,返回mapped的引用)
clear(清空键值对)
insert(参数为键值对引用,返回一对pair<iterator,bool>,iter指向改键值对,无论是否已存在,bool表示是否成功添加,如为false则已存在该键值对)
erase(key为参数,返回bool值)
earse(iter为参数,返回该指针下一个位置)
rehash(size_t为参数,重新哈希为给出的新的指针数组大小)
begin(根据hashmap是否为const给出iter或const iter)
end(返回伪指针)
debug(打印所有哈希键值对以及哈希表所有参数,注意,必须基于重载<<运算符的基础)

符号重载:
M& [](const key& ,返回insert(key)的返回pair的first成员的second成员,即mapped值)
//用于给key对应的value(mapped)赋值

private:
node(struct,包含next指针和value)
nodepair(前后node的pair)
findnode(参数key,返回指针对<prev,curr>)
first_not_empty_bucket()
make_iterator(参数node*curr)
_bucket_array(vector<node*>,其中一个node*为ptr,则ptr->value为<key ,mapped>)

//指针构造

_bucket_array:由指针组成的数组,每个成员都是一个指针
储存的值为next指针和一个pair<key,mapped>
operator-> is a bit of an odd-ball. When you write p->m, it is interpreted as (p.operator->())->m.

- This means operator-> should return a pointer to the object that has the field m.

涉及的c++特性

匿名函数 基本lambda语法 基本形式如下: 【capture】(parameters)->return-type {body}

typename function() return {x,y,z} 即用{}的参数初始化原函数返回的类型

ptrdiff_t:用于储存两个指针的差

conditional_t<func,x,y>如果func为true则x,为false则y

forward_iterator_tag:单方向迭代器(可读写) ++iter,iter+=1随后返回对自身的引用 iter++,先返回一个对自身的复制,随后iter+=1

std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);

ate:从文件尾部开始 strsub(start,length) 移动语义(c++11新特性) clss(classname &&) 利用右值引用的部分数据直接初始化新的类,并在初始化之后将右值删除,可以通过std::move()强制转化左值为右值。

]]>
- <h2 id="一些查找和排序算法">一些查找和排序算法</h2> -<p>二分查找法 <img src="/images/obsidian/20230226101843.png" title="image" alt="图片" /> 最坏情况:log2n + <h2 id="c特性">c++特性</h2> +<ul> +<li>更好的C C++支持<code>命令式编程</code>,一种编程风格,其中程序按顺序执行的命令序列。从这个意义上讲,C++ 可以看作是对C 编程语言,使日常命令式编程更加直观和更容易使用。课程阅读器的这一部分介绍了一些 C++ 最常用的库,包括标准模板库,并展示了如何使用这些库来构建命令程式。 此外,它探索了最初出现在 C++ 语言中的新原语。C 编程语言,即指针、C 字符串和预处理器。 @@ -1064,8 +1070,6 @@ A.L.I.C.E(原曲:不可思议之国的爱丽丝)<br /> - - @@ -1073,18 +1077,17 @@ A.L.I.C.E(原曲:不可思议之国的爱丽丝)<br />
- 基于斯坦福cs106l的c++编程规范笔记 - - https://thinklive1.github.io/thinklive/48468/ + 基于斯坦福cs106b的c++数据结构笔记 + + https://thinklive1.github.io/thinklive/16615/ 2024-01-20T11:53:48.573Z 2023-11-27T12:47:59.687Z - c++特性
  • 更好的C C++支持命令式编程,一种编程风格,其中程序按顺序执行的命令序列。从这个意义上讲,C++ 可以看作是对C 编程语言,使日常命令式编程更加直观和更容易使用。课程阅读器的这一部分介绍了一些 C++ 最常用的库,包括标准模板库,并展示了如何使用这些库来构建命令程式。 此外,它探索了最初出现在 C++ 语言中的新原语。C 编程语言,即指针、C 字符串和预处理器。
  • 数据抽象

C++与其兄弟C的最大区别在于_数据抽象_,程序执行的方式可以与程序执行的方式分开 程序员谈论那个程序。

  • 面向对象编程

. 面向对象编程是一种完全不同的方式考虑程序设计,可以极大地简化复杂的软件系统。 钥匙 面向对象背后的概念很简单,但要真正体会到面向对象的力量 编程,您将需要一次又一次地看到它的运行情况。 这部分课程 读者探索了面向对象编程中的主要概念以及如何在 C++ 中实现它继承和多态。

  • 泛型编程

泛型编程是一种编程风格,旨在构建可以解决一系列远远超出最初设想的问题的软件
履行。 虽然泛型编程的完整处理远远超出了介绍性的范围C++ 编程课,泛型编程的许多思想都可以访问并且可以从根本上改变了您对 C++ 编程的看法。

const

Can’t declare non-const reference to const variable Can’t declare non-const reference to const vari

图片 图片

模板

图片 函数指针:将函数作为对象传递

stl

sequence:线性,有顺序 associative:不一定线性,有索引机制(map)

vector:有顺序的相同类型的数据集合,大小可控制 ---子属性:size:元素数量 ---capacity:单个元素大小 图片 vector最常用,deque用于首部插入场合,list用于多种列表

associative(关联数组):有顺序的需要有比较方法,无序的需要哈希函数(更快) iterators(迭代器):用于访问容器中的所有数据 --常用函数,begin(),end(),iter++,*(pointer),== !=,=(赋值,复制), 图片 图片 图片

输入输出流

First call to std::cin >> creates a command line
prompt that allows the user to type until they hit enter

  • Each >> ONLY reads until the next whitespace
  • Whitespace = tab, space, newline
  • Everything after the first whitespace gets saved and
    used the next time std::cin >> is called
  • The place its saved is called a buffer 图片 图片 图片 图片 图片 图片 图片

hashmap的c++实现

相关函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
构造函数HashMap():
接受参数count(值的个数),hash function(有默认值)

参数(typename fitst,typename last,bucket_count,H)
//用一个容器首尾指针初始化hashmap
eg.
hashmap<k,m> map{vec.begin(),vec.end()}

参数(init_list init,bucket_count,H)
//用容器直接初始化hashmap
eg.
HashMap<char, int> map{{'a', 3}, {'b', 5}, {'c', 7}};

public:
key-键
mapped-被加密的值(int)
H-哈希函数
bucket_count(存储的键值对数组容量)
load_factor(内联函数,返回size/bucket_count,即实际储存值的键值对)
contains(参数const K& key判断是否存在改键,返回bool值)
at(参数k,返回mapped的引用)
clear(清空键值对)
insert(参数为键值对引用,返回一对pair<iterator,bool>,iter指向改键值对,无论是否已存在,bool表示是否成功添加,如为false则已存在该键值对)
erase(key为参数,返回bool值)
earse(iter为参数,返回该指针下一个位置)
rehash(size_t为参数,重新哈希为给出的新的指针数组大小)
begin(根据hashmap是否为const给出iter或const iter)
end(返回伪指针)
debug(打印所有哈希键值对以及哈希表所有参数,注意,必须基于重载<<运算符的基础)

符号重载:
M& [](const key& ,返回insert(key)的返回pair的first成员的second成员,即mapped值)
//用于给key对应的value(mapped)赋值

private:
node(struct,包含next指针和value)
nodepair(前后node的pair)
findnode(参数key,返回指针对<prev,curr>)
first_not_empty_bucket()
make_iterator(参数node*curr)
_bucket_array(vector<node*>,其中一个node*为ptr,则ptr->value为<key ,mapped>)

//指针构造

_bucket_array:由指针组成的数组,每个成员都是一个指针
储存的值为next指针和一个pair<key,mapped>
operator-> is a bit of an odd-ball. When you write p->m, it is interpreted as (p.operator->())->m.

- This means operator-> should return a pointer to the object that has the field m.

涉及的c++特性

匿名函数 基本lambda语法 基本形式如下: 【capture】(parameters)->return-type {body}

typename function() return {x,y,z} 即用{}的参数初始化原函数返回的类型

ptrdiff_t:用于储存两个指针的差

conditional_t<func,x,y>如果func为true则x,为false则y

forward_iterator_tag:单方向迭代器(可读写) ++iter,iter+=1随后返回对自身的引用 iter++,先返回一个对自身的复制,随后iter+=1

std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);

ate:从文件尾部开始 strsub(start,length) 移动语义(c++11新特性) clss(classname &&) 利用右值引用的部分数据直接初始化新的类,并在初始化之后将右值删除,可以通过std::move()强制转化左值为右值。

]]>
+ 一些查找和排序算法

二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

容器类

set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

哈希表

哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

检查表中是否存在元素

● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

将元素插入表中

● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

从表中删除一个元素

● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

“罗宾汉哈希表”

  • 如果插入的值比其将插入的位置的值距离索引更远,则替换插入值和当前值
  • 删除值时,将后其离原键远的元素前移
  • ★ 罗宾汉哈希一览 ★
  • 检查表中是否存在元素:
  • ● 跳转到表中由元素的散列码给出的位置。
  • ● 向前扫描——如有必要环绕——记录有多少步 你拿走了。 当您找到该项目、找到一个空白槽或找到一个 离家更近的空位比你走的步数还多。
  • 将元素插入表中:
  • ● 如果该元素已在表中,则什么也不做。
  • ● 跳转到由元素的散列码给出的表槽。 向前扫描 - 换行 如有必要,四处走走——记录所走的步数。 如果你找到一个 空插槽,将元素放在那里。 否则,如果当前插槽已满并且 比您插入的元素更靠近家,将要插入的项目放在那里, 替换那个位置的元素,然后继续插入,就好像你 正在插入被置换的元素。
  • 从表中删除一个元素:
  • ● 跳转到由元素的散列码给定的槽。
  • ● 向前走——如有必要,环绕——直到物品或空槽被放置 成立。 如果找到该项目,请将其删除。 然后,继续前进——包裹 around as necessary – 将表中的元素向后移动一个槽位,直到 找到空插槽或位于其原始位置的项目

string类

str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// count is npos, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

// both pos and pos+count are within bounds, returns [pos, pos+count)
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

// pos is within bounds, pos+count is not, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
// this is effectively equivalent to
// std::string sub4 = a.substr(17, 3);
// since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

try {
// pos is out of bounds, throws
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
} catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
}
}
输出:
abcdefghij
567
hij
pos exceeds string size

`replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

一些实现

优先队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include "HeapPQueue.h"
using namespace std;

HeapPQueue::HeapPQueue() {
elems = new DataPoint[INITIAL_SIZE] {};
for (int i=0;i<INITIAL_SIZE;i++)
{
elems[i].weight=0;
}
allocatedSize=INITIAL_SIZE;
}

HeapPQueue::~HeapPQueue() {
delete [] elems;
}

int HeapPQueue::size() const {
return logicalSize;
}

bool HeapPQueue::isEmpty() const {
return logicalSize==0;
}

void HeapPQueue::enqueue(const DataPoint& data) {
if (logicalSize+1<allocatedSize)
{
if (logicalSize==0)
{
elems[1]=data;
logicalSize++;
}
else
{
logicalSize++;
int i=1;
while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
{
i++;
}
if (i<logicalSize)
{
DataPoint temp=elems[i];
elems[i]=data;
for(i;i<logicalSize;i++)
{
DataPoint temp_plus=elems[i+1];
elems[i+1]=temp;
temp=temp_plus;

}
}
else
{
elems[i]=data;
}

}
}
}

DataPoint HeapPQueue::peek() const {
return elems[logicalSize];
}

DataPoint HeapPQueue::dequeue() {
DataPoint to_return=elems[1];
if(!isEmpty())
{

for (int i=1;i<logicalSize;i++)
{
elems[i]=elems[i+1];
}
elems[logicalSize]={};
logicalSize--;
}
return to_return;
}

计数排序

首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Given a Vector<int>, returns the largest number in that Vector. */
int maxOf(const Vector<int>& values) {
/* Bounds-check inputs. */
if (values.isEmpty()) {
error("Can't find the maximum of no values.");
}

int result = values[0];
for (int i = 1; i < values.size(); i++) {
result = max(result, values[i]);
}
return result;
}

/* Given a list of numbers, creates a histogram from those numbers. */
Vector<int> histogramFor(const Vector<int>& values) {
/* Create a histogram with the right number of slots. Initially, all values
* in the histogram will be zero.
*/
Vector<int> histogram(maxOf(values) + 1);

/* Scan across the input vector, incrementing the histogram values. */
for (int value: values) {
histogram[value]++;
}

return histogram;
}

void countingSort(Vector<int>& values) {
/* Edge Case: If the array is empty, then it's already sorted. This is
* needed because we can't take the maximum value of an empty vector.
*/
if (values.isEmpty()) {
return;
}

/* Form the histogram. */
auto histogram = histogramFor(values);

/* Scan across the histogram writing out the appropriate number of copies
* of each value. We track the index of the next free spot to write to,
* as it varies based on how many items we've written out so far.
*/
int next = 0;
for (int value = 0; value < histogram.size(); value++) {
/* Write out the right number of copies. */
for (int copy = 0; copy < histogram[value]; copy++) {
values[next] = value;
next++;
}
}
}

错题集

递归的效率优化

每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

递归计算给定元素的不同结构哈夫曼树的数量

对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numBSTsOfSize(int n) {

/* Base case: There’s only one tree of size 0, namely, the empty BST. */
if (n == 0) return 1;

/* Recursive case: Imagine all possible ways to choose a root and build the
* left and right subtrees.
*/
int result = 0;

/* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
for (int i = 0; i < n; i++) {
/* Each combination of a BST of i elements and a BST of n - 1 - i elements
* can be used to build one BST of n elements. The number of pairs of
* trees we can make this way is given by the product of the number of
* trees of each type.
*/
result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
}

return result;
}

递归解决吃巧克力问题

求出吃法数量

1
2
3
4
5
6
7
8
9
10
11
12
if (numSquares<0)
{
error("输入数据不能为负数");
}
else if (numSquares<=1)
{
return 1;
}
else
{
return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
}

打印每种吃法

`需要一个辅助向量储存历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Print all ways to eat numSquares more squares, given that we've
* already taken the bites given in soFar.
*/
void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
/* Base Case: If there are no squares left, the only option is to use
* the bites we've taken already in soFar.
*/
if (numSquares == 0) {
cout << soFar << endl;
}
/* Base Case: If there is one square lfet, the only option is to eat
* that square.
*/
else if (numSquares == 1) {
cout << soFar + 1 << endl;
}
/* Otherwise, we take take bites of size one or of size two. */
else {
printWaysToEatRec(numSquares - 1, soFar + 1);
printWaysToEatRec(numSquares - 2, soFar + 2);
}
}

void printWaysToEat(int numSquares) {
if (numSquares < 0) {
error("You owe me some chocolate!");
}

/* We begin without having made any bites. */
printWaysToEatRec(numSquares, {});
}

递归解决翻煎饼问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
bool isSorted(Stack<double> pancakes) {
double last = -1; // No pancakes have negative size;

while (!pancakes.isEmpty()) {
/* Check the next pancake. */
double next = pancakes.pop();
if (next < last) {
return false;
}

last = next;
}

/* Pancakes are in increasing order! */
return true;
}

/* Given a stack of pancakes and a flip size, flips that many pancakes
* on the top of the stack.
*/
Stack<double> flip(Stack<double> pancakes, int numToFlip) {
/* Take the top pancakes off the stack and run them into a queue.
* This preserves the order in which they were removed.
*/
Queue<double> buffer;
for (int i = 0; i < numToFlip; i++) {
buffer.enqueue(pancakes.pop());
}

/* Move the pancakes back. */
while (!buffer.isEmpty()) {
pancakes.push(buffer.dequeue());
}

return pancakes;
}

Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
/* Base Case: If the stack is sorted, great! We're done, and no flips
* were needed.
*/
if (isSorted(pancakes)) {
return { }; // No flips
}
/* Base Case: If the stack isn't sorted and we're out of flips, then
* there is no way to sort things.
*/
else if (numFlips == 0) {
return Nothing;
}
/* Recursive Case: The stack isn't sorted and we still have flips left.
* The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
* Try each option and see whether any of them work.
*/
for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
/* Make the flip and see if it works. */
auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
if (result != Nothing) {
/* The result holds all the remaining flips but doesn't know about
* the flip we just did. Insert that flip at the beginning.
*/
result.value().insert(0, numToFlip);
return result;
}
}

/* If we're here, then no matter which flip we make first, we cannot
* get the pancakes sorted. Give up.
*/
return Nothing;
}

递归解决天平问题

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
if (index == weights.size()) {
return amount == 0;
} else {
return isMeasurableRec(amount, weights, index + 1) ||
isMeasurableRec(amount + weights[index], weights, index + 1) ||
isMeasurableRec(amount - weights[index], weights, index + 1);
}
}

bool isMeasurable(int amount, const Vector<int>& weights) {
return isMeasurableRec(amount, weights, 0);
}

想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

  • 向左走,使规模上的净不平衡 n + w ,或
  • 向右走,使规模上的净不平衡 n – w ,或
  • 根本不习惯,留下净不平衡 n

如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

递归解决找零问题

不使用记忆的情况

`从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}
/* Base case: You need no coins to give change for no cents. */
else if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (coins.isEmpty()) {
return cents + 1;
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;
/* Pick a coin. */
int coin = coins.first();
/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
coins - coin);
/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}
/* Return whatever worked best. */
return bestSoFar;
}
}

使用记忆进行优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* How few coins are needed to make the total, given that we can only use
* coins from index startIndex and onward?
*/
int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
/* Base case: You need no coins to give change for no cents. */
if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (startIndex == coins.size()) {
return cents + 1;
}
/* Base case: We already know the answer. */
else if (memo[cents][startIndex] != -1) {
return memo[cents][startIndex];
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;

/* Pick a coin. */
int coin = coins[startIndex];

/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
coins, startIndex + 1,
memo);

/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}

/* Return whatever worked best. */
memo[cents][startIndex] = bestSoFar;
return bestSoFar;
}
}

int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}

/* Convert from a Set<int> to a Vector<int> so we have a nice ordering
* on things.
*/
Vector<int> coinVec;
for (int coin: coins) {
coinVec += coin;
}

/* Build our memoization table. Since the number of cents left ranges from
* 0 to cents, we need cents+1 rows. Since the start index of the coin
* ranges from 0 to coins.size(), we make coins.size() + 1 columns.
*
* -1 is used as a sentinel to indicate "nothing has been computed here
* yet."
*/
Grid<int> memo(cents + 1, coins.size() + 1, -1);

/* Now ask how many coins are needed to make the total, using any coins
* from index 0 onward.
*/
return fewestCoinsRec(cents, coinVec, 0, memo);
}

递归穷举付账单

递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
/* Base case: if there's one person left, they have to pay the whole bill. */
if (people.size() == 1) {
Map<string, int> finalPayments = payments;
finalPayments[people.first()] = total;
cout << finalPayments << endl;
}
/* Recursive case: The first person has to pay some amount between 0 and the
* total amount. Try all of those possibilities.
*/
else {
for (int payment = 0; payment <= total; payment++) {
/* Create a new assignment of people to payments in which this first
* person pays this amount.
*/
Map<string, int> updatedPayments = payments;
updatedPayments[people.first()] = payment;
listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
}
}
}
void listPossiblePayments(int total, const Set<string>& people) {
/* Edge cases: we can't pay a negative total, and there must be at least one
* person.
*/
if (total < 0) error("Guess you're an employee?");
if (people.isEmpty()) error("Dine and dash?");
listPossiblePaymentsRec(total, people, {});
}

递归寻找完全平方数列

主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Optional<Vector<int>> findSquareSequence(int n) {
/*Validate input.*/
if (n < 0) {
error("Don't be so negative!");
}

/* Build a set of the numbers 1, 2, 3, ..., n. */
Set<int> options;
for (int i = 1; i <= n; i++) {
options += i;
}
return findSequenceRec(options, { });
}

Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
const Vector<int>& soFar) {
/*Base Case: If all numbers are used, we have our sequence!*/
if (unused.isEmpty()) {
return soFar;
}

/* Recursive Case: Some number comes next. Try each of them and see which
* one we should pick.
*/
for (int next: unused) {
/* We can use this if either
*
* 1. the sequence is empty, so we're first in line, or
* 2. the sequence is not empty, but we sum to a perfect square
* with the previous term.
*/
if (soFar.isEmpty() ||
isPerfectSquare(next + soFar[soFar.size() - 1])) {
/* See what happens if we extend with this number. */
auto result = findSequenceRec(unused - next, soFar + next);
if (result != Nothing) {
return result;
}
}
}

/* Tried all options and none of them worked. Oh well! */
return Nothing;
}

汉诺塔递归

假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

1
2
3
4
5
6
7
8
9
10
11
int moveTower(int numDisks, char start, char finish, char temp) {
if (numDisks == 0) {
return 0;
} else {
int movesOne = moveTower(numDisks - 1, start, temp, finish);
moveSingleDisk(start, finish);
int movesTwo = moveTower(numDisks - 1, temp, finish, start);

return 1 + movesOne + movesTwo;
}
}
]]>
- <h2 id="c特性">c++特性</h2> -<ul> -<li>更好的C C++支持<code>命令式编程</code>,一种编程风格,其中程序按顺序执行的命令序列。从这个意义上讲,C++ 可以看作是对C 编程语言,使日常命令式编程更加直观和更容易使用。课程阅读器的这一部分介绍了一些 C++ 最常用的库,包括标准模板库,并展示了如何使用这些库来构建命令程式。 此外,它探索了最初出现在 C++ 语言中的新原语。C 编程语言,即指针、C 字符串和预处理器。 + <h2 id="一些查找和排序算法">一些查找和排序算法</h2> +<p>二分查找法 <img src="/images/obsidian/20230226101843.png" title="image" alt="图片" /> 最坏情况:log2n @@ -1095,6 +1098,8 @@ A.L.I.C.E(原曲:不可思议之国的爱丽丝)<br /> + + diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" index 3bee5cc0d..30df3d448 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" @@ -266,8 +266,8 @@

black souls
-
@@ -286,8 +286,8 @@

black souls
-
diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" index 00394302c..f320529be 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" @@ -266,8 +266,8 @@

游戏杂谈
-
@@ -286,8 +286,8 @@

游戏杂谈
-
diff --git "a/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" "b/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" index 4fe13f045..0e31b608a 100644 --- "a/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" +++ "b/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" @@ -266,7 +266,7 @@

考研笔记
-
diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" index 6cce5bb75..ff26e29f6 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" @@ -326,8 +326,8 @@

课程笔记
-
@@ -346,8 +346,8 @@

课程笔记
-
@@ -366,8 +366,8 @@

课程笔记
-
@@ -386,8 +386,8 @@

课程笔记
-
@@ -406,8 +406,8 @@

课程笔记
-
diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" index 9e22ddc3d..eaec2ef7b 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" @@ -306,8 +306,8 @@

数据结构与算法
-
@@ -326,8 +326,8 @@

数据结构与算法
-
diff --git a/index.html b/index.html index 2560d3f00..6387f9038 100644 --- a/index.html +++ b/index.html @@ -363,7 +363,7 @@

更新日志

- +

- +

-
@@ -286,8 +286,8 @@

black souls
-
diff --git a/tags/c/index.html b/tags/c/index.html index ee1bfd3c4..24ceea8ee 100644 --- a/tags/c/index.html +++ b/tags/c/index.html @@ -286,8 +286,8 @@

c++
-
@@ -306,8 +306,8 @@

c++
-
diff --git "a/tags/\346\226\257\345\235\246\347\246\217/index.html" "b/tags/\346\226\257\345\235\246\347\246\217/index.html" index 1ed659c38..44a87f641 100644 --- "a/tags/\346\226\257\345\235\246\347\246\217/index.html" +++ "b/tags/\346\226\257\345\235\246\347\246\217/index.html" @@ -266,8 +266,8 @@

斯坦福
-
@@ -286,8 +286,8 @@

斯坦福
-
diff --git "a/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" "b/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" index bb2067693..873de406c 100644 --- "a/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" +++ "b/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" @@ -266,8 +266,8 @@

游戏杂谈
-
@@ -286,8 +286,8 @@

游戏杂谈
-
diff --git "a/tags/\347\240\224distance/index.html" "b/tags/\347\240\224distance/index.html" index 9c20f9838..13a672d57 100644 --- "a/tags/\347\240\224distance/index.html" +++ "b/tags/\347\240\224distance/index.html" @@ -266,7 +266,7 @@

研distance
-
diff --git "a/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" "b/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" index b792cfdc1..e9e95d83f 100644 --- "a/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" +++ "b/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" @@ -306,8 +306,8 @@

课程笔记
-
@@ -326,8 +326,8 @@

课程笔记
-
diff --git a/thinklive/11069/index.html b/thinklive/11069/index.html index 911b1262b..5aff4647c 100644 --- a/thinklive/11069/index.html +++ b/thinklive/11069/index.html @@ -671,8 +671,8 @@

还有更多的 Vim 小窍门吗?
-
diff --git a/thinklive/11086/index.html b/thinklive/11086/index.html index 7ae30d9c4..d66d77caa 100644 --- a/thinklive/11086/index.html +++ b/thinklive/11086/index.html @@ -444,8 +444,8 @@

进阶

-
diff --git a/thinklive/15197/index.html b/thinklive/15197/index.html index 0a2231d95..e3810f614 100644 --- a/thinklive/15197/index.html +++ b/thinklive/15197/index.html @@ -461,8 +461,8 @@

匿名函数

-
diff --git a/thinklive/15575/index.html b/thinklive/15575/index.html index c81273863..185cfda09 100644 --- a/thinklive/15575/index.html +++ b/thinklive/15575/index.html @@ -441,8 +441,8 @@

slides实例

-
diff --git a/thinklive/16615/index.html b/thinklive/16615/index.html index c5139ee3c..6a34bd59a 100644 --- a/thinklive/16615/index.html +++ b/thinklive/16615/index.html @@ -448,13 +448,13 @@

汉诺塔递归

-
-
diff --git a/thinklive/22586/index.html b/thinklive/22586/index.html index efbce6577..330d459c4 100644 --- a/thinklive/22586/index.html +++ b/thinklive/22586/index.html @@ -574,13 +574,13 @@

js动效

-
-
diff --git a/thinklive/23089/index.html b/thinklive/23089/index.html index cccb320b3..6dadcaa4a 100644 --- a/thinklive/23089/index.html +++ b/thinklive/23089/index.html @@ -349,7 +349,7 @@

-
diff --git a/thinklive/24757/index.html b/thinklive/24757/index.html index c1b7b26ee..4bdab44c0 100644 --- a/thinklive/24757/index.html +++ b/thinklive/24757/index.html @@ -381,13 +381,13 @@

gitbub

-
-
diff --git a/thinklive/27780/index.html b/thinklive/27780/index.html index 1fd8e41ff..d67a03309 100644 --- a/thinklive/27780/index.html +++ b/thinklive/27780/index.html @@ -625,13 +625,13 @@

javaweb

-
-
diff --git a/thinklive/2910/index.html b/thinklive/2910/index.html index 7d600bca0..3d66ecd4e 100644 --- a/thinklive/2910/index.html +++ b/thinklive/2910/index.html @@ -2016,8 +2016,8 @@

访问控制权限和分组

-
diff --git a/thinklive/29916/index.html b/thinklive/29916/index.html index f1e5880eb..7a1aa9652 100644 --- a/thinklive/29916/index.html +++ b/thinklive/29916/index.html @@ -543,8 +543,8 @@

ex03

-
diff --git a/thinklive/30989/index.html b/thinklive/30989/index.html index 36ae0ee22..840220f48 100644 --- a/thinklive/30989/index.html +++ b/thinklive/30989/index.html @@ -416,13 +416,13 @@

题外话

-
-
diff --git a/thinklive/36218/index.html b/thinklive/36218/index.html index 4a64d4aba..8a52b0779 100644 --- a/thinklive/36218/index.html +++ b/thinklive/36218/index.html @@ -712,13 +712,13 @@

be

-
-
diff --git a/thinklive/39056/index.html b/thinklive/39056/index.html index 60f5ebf14..3bf5338f6 100644 --- a/thinklive/39056/index.html +++ b/thinklive/39056/index.html @@ -1829,13 +1829,13 @@

交叉验证

-
-
diff --git a/thinklive/48368/index.html b/thinklive/48368/index.html index f7fc1777d..bb43b3f58 100644 --- a/thinklive/48368/index.html +++ b/thinklive/48368/index.html @@ -489,13 +489,13 @@

npc dreams

-
-
diff --git a/thinklive/48468/index.html b/thinklive/48468/index.html index 15be217f5..1808a019d 100644 --- a/thinklive/48468/index.html +++ b/thinklive/48468/index.html @@ -426,13 +426,13 @@

涉及的c++特性

-
-
diff --git a/thinklive/54551/index.html b/thinklive/54551/index.html new file mode 100644 index 000000000..3f89c16bb --- /dev/null +++ b/thinklive/54551/index.html @@ -0,0 +1,564 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +暑期复习日活 | thinklive + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+
+
+ + +
+ + + +

thinklive

+ +
+

dirichlet library

+
+ + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + + +
+ + + +
+ + + + + + + +
+

+ 暑期复习日活 +

+ + +
+ + + + + +

删除线表示完成,未完成日后补上视为完成

+

2024/6/17
+单词200次
+操作系统二轮复习——80%
+计算机网络二轮复习——20%
+英语真题训练

+

2024/6/18
+单词200次 李永乐线代——矩阵部分例题50%
+英语真题训练

+

2024/6/19(完成课程作业因此工作量减半)
+单词200次
+操作系统二轮复习——100%~~
+李永乐线代——矩阵部分例题75%~~

+

2024/6/20 单词150次
+计算机网络二轮复习——40%~~
+李永乐线代——矩阵部分例题100%~~
+李永乐线代——矩阵部分练习题100%~~
+英语真题训练~~

+ + +
+ + + + + + +
+
+ + + + + + +
+
+
+ +
+ +
+ + +
+ + 0% +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +