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";
/* 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++; } } }
/* 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); }
/* 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, {}); }
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); } }
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; } }
/* 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; } }
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); }
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, {}); }
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; }