01 - 25  
3.数组中重复的数字 
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
 
 
输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3 
 
 
方法:
 
 
 
哈希表 
sort后,进行查找 
元素交换到其下标对应位置(最优解) 
 
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 int  findRepeatNumber (vector <int >& nums)   {	 	 	 	 	 	 	 	 	 	 	 	 	 	 	for  (int  i = 0 ; i < nums.size (); i++) { 		if  (nums[i] != i) { 			if  (nums[i] == nums[nums[i]]) 				return  nums[i]; 			else  { 				int  temp = nums[i]; 				nums[i] = nums[temp]; 				nums[temp] = temp; 			} 		} 	} 	return  -1 ; } 
 
 
4.二维数组中的查找 
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
 
 
输入:
 
 
[
 
[1,   4,  7, 11, 15],
 
[2,   5,  8, 12, 19],
 
[3,   6,  9, 16, 22],
 
[10, 13, 14, 17, 24],
 
[18, 21, 23, 26, 30]
 
]
 
给定 target = 5,返回 true。
 
给定 target = 20,返回 false。
 
 
方法:
 
 
特征:矩阵,从左至右,从上至下依次递增 
使用:线性查找,从有右上角开始查询 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 bool  findNumberIn2DArray (vector <vector <int >>& matrix, int  target)   {	if  (matrix.size () == 0 ) 		return  false ; 	 	 	int  m = matrix.size (); 	int  n = matrix[0 ].size (); 	int  row = 0 ; 	int  col = n - 1 ; 	while  (row < m && col >= 0 ) { 		if  (matrix[row][col] == target) 			return  true ; 		else  if  (matrix[row][col] > target) 			col--; 		else  			row++; 	} 	return  false ; } 
 
 
5.替换空格 
请实现一个函数,把字符串 s 中的每个空格替换成”%20”。
 
 
输入:
 
 
 
输入:s = “We are happy.”
输出:”We%20are%20happy.”
新的string,遍历后增加替换 
string的成员函数replace,A.replace(i_开始的下标 , len_长度 , “替换的字符”) 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 string  replaceSpace (string  s)   {	 	 	 	 	 	 	 	 	 	 	if  (s.size () == 0 ) return  s; 	for  (int  i = 0 ; i < s.size (); i++) { 		if  (s[i] == ' ' ) 			s.replace(i, 1 , "%20" ); 	} 	return  s; } 
 
 
6.从头到尾打印链表 
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
 
 
输入:
 
 
输入:head = [1,3,2]
 
输出:[2,3,1]
 
方法:
 
 
 
利用deque 
利用vector(倒置初始化)/ reserve 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 vector <int > reversePrint (ListNode* head)   {	 	 	 	 	 	 	vector <int > deq; 	while  (head != NULL ) { 		deq.push_back(head->val); 		head = head->next; 	} 	vector <int >arr(deq.rbegin(), deq.rend()); 	return  arr; } 
 
 
7.    重建二叉树 
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 
 
输入:
 
 
前序遍历 preorder = [3,9,20,15,7]
 
中序遍历 inorder = [9,3,15,20,7]
 
方法:
 
 
反复利用数组的下标初始化
 
先序——定根
 
中序——定区间
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 TreeNode* buildTree (vector <int >& preorder, vector <int >& inorder)   {	return  build(preorder, inorder, 0 , 0 , preorder.size () - 1 ); }                           TreeNode* build (vector <int >& preorder, vector <int >& inorder, int  root, int  start, int  end )   {	if  (start > end ) 		return  NULL ; 	 	TreeNode* tree = new  TreeNode(preorder[root]); 	     	 	int  i = start; 	while  (i < end  &&preorder[root] != inorder[i]) 		i++; 					 	tree->left = build(preorder, inorder, root + 1 , 	start, i - 1 ); 	tree->right = build(preorder, inorder, root + 1  + i - start, i + 1 ,  end ); 	return  tree; } 
 
 
9.用两个栈实现队列 
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
 
 
输入:略
 
 
 
利用两个栈 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 stack <int >s1;stack <int >s2;void  appendTail (int  value)   {	while  (!s1.empty()) { 		int  temp = s1.top(); 		s2.push(temp); 		s1.pop(); 	} 	s1.push(value); 	while  (!s2.empty()) { 		int  temp = s2.top(); 		s1.push(temp); 		s2.pop(); 	} } int  deleteHead ()   {	if  (s1.empty()) 		return  -1 ; 	int  temp = s1.top(); 	s1.pop(); 	return  temp; } 
 
 
10-1.斐波那契数列 
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
 
 
 
F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
输入:n = 2 输出:1
输入:n = 5 输出:5
dp方程 
a = a + b、b = a - b 
 
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 int  fib (int  n)   {	 	 	 	 	 	 	 	 	 	 	 	if  (n == 0 )return  0 ; 	if  (n <= 2 )return  1 ; 	int  a = 1 ; 	int  b = 0 ; 	for  (int  i = 2 ; i <= n; i++) { 		a = a + b; 		b = a - b; 		a %= 1000000007 ; 	} 	return  a; } 
 
 
10-2 .青蛙跳台阶问题 
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
 
 
 
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
 
11.    旋转数组的最小数字 
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。  
 
 
 
输入:
 
 
输入:[3,4,5,1,2]
 
输出:1
 
输入:[2,2,2,0,1]
 
 
输出:0
 
解:就是找到最小的那个数,就是导致数组旋转
 
 
方法:
 
 
 
二分法 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int  minArray (vector <int >& numbers)   {	 	if  (numbers.size () == 1 )return  numbers[0 ]; 	int  L = 0 , R = numbers.size () - 1 ; 	while  (L < R) { 		 		int  mid = (L + R) / 2 ; 		if  (numbers[mid] < numbers[R]) {   			R = mid; 		} 		else  if  (numbers[mid] > numbers[R]) { 			L = mid + 1 ; 		} 		else  			R--; 	} 	return  numbers[L]; } 
 
 
12.矩阵中的路径 
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
 
 
 
输入:
 
 
[[“a”,“b” ,”c”,”e”], 
[“s”,“f” ,“c” ,”s”], 
[“a”,”d”,“e” ,”e”]] 
“bfce” ,true 
 
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 bool  exist (vector <vector <char >>& board, string  word )   {	int  len = board.size (); 	if  (len == 0  || board[0 ].size () == 0  || word .empty())return  false ; 	vector <vector <bool >>vis(len, vector <bool >(board[0 ].size (), true )); 	for  (int  i = 0 ; i < board.size (); i++) { 		for  (int  j = 0 ; j < board[0 ].size (); j++) { 			if  (board[i][j] == word [0 ]) { 				if  (dfs(i, j, board, word , 0 , vis)) 					return  true ; 			} 		} 	} 	return  false ; } bool  dfs (int  i, int  j, vector <vector <char >>& board, string  word , int  length, vector <vector <bool >>&vis)   {	 	if  (length == word .size ()) 		return  true ; 	 	if  (i < 0  || i >= board.size () || j < 0  || j >= board[0 ].size () || vis[i][j] == false  || board[i][j] != word [length]) 		return  false ; 	 	vis[i][j] = false ; 	 	bool  res = dfs(i, j + 1 , board, word , length + 1 , vis) || dfs(i, j - 1 , board, word , length + 1 , vis) || 		dfs(i + 1 , j, board, word , length + 1 , vis) || dfs(i - 1 , j, board, word , length + 1 , vis); 	 	vis[i][j] = true ; 	return  res; } 
 
 
13.    机器人的运动范围 
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
 
 
 
输入: 输入:m = 2, n = 3, k = 1 输出:3
 
 
 
输入:m = 3, n = 1, k = 0 输出:1
典型的BFS,但是只有两个方向需要注意 
 
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 int  get (int  x)   {	int  res = 0 ; 	while  (x) { 		res += x % 10 ; 		x /= 10 ; 	} 	return  res; } int  movingCount (int  m, int  n, int  k)   {	if  (!k) return  1 ; 	vector <vector <int >>vis(m, vector <int >(n, 0 )); 	vis[0 ][0 ] = 1 ; 	queue <pair<int , int >> Q; 	Q.push(make_pair(0 , 0 )); 	int  dx[2 ] = { 0 , 1  }; 	int  dy[2 ] = { 1 , 0  }; 	int  ans = 1 ; 	while  (!Q.empty()) { 		auto [x, y] = Q.front(); 		Q.pop(); 		for  (int  i = 0 ; i < 2 ; ++i) { 			int  tx = dx[i] + x; 			int  ty = dy[i] + y; 			if  (tx >= 0  && tx < m && ty >= 0  && ty < n && 				get (tx) + get (ty) < k + 1  && vis[tx][ty] == 0 ) { 				Q.push(make_pair(tx, ty)); 				vis[tx][ty] = 1 ; 				ans++; 			} 		} 	} 	return  ans; } 
 
 
14-1.剪绳子 
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1] …*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
 
 
 
输入: 输入: 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1
 
 
 
输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
解:只有绳子大于4的时候,才需要剪开可以乘积变大
 
1  /  1  0 
2  /  1*1=1 
3  /  1*2=2 
4  /  2*2=4 
5  /  2*3=5  //开始变化 
 
 
方法:
 
 
 
找规律 
dp动态规划 
 
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 int  cuttingRope (int  n)   {	 	 	 	 	 	 	 	 	 	if  (n < 4 )return  n - 1 ; 	if  (n == 4 )return  4 ; 	vector <int > dp (n + 1 )  ; 	dp[1 ] = 1 ; 	dp[2 ] = 2 ; 	dp[3 ] = 3 ; 	dp[4 ] = 4 ; 	for  (int  i = 5 ; i <= n; i++) { 		int  maxNum = 0 ; 		for  (int  j = 1 ; j <= i / 2 ; j++) { 			maxNum = max (maxNum, dp[i - j] * dp[j]); 		} 		dp[i] = maxNum; 	} 	return  dp[n]; } 
 
 
14-2.剪绳子 II 
 
15.二进制中1的个数 1 2 3 4 5 6 7 8 9 int  hammingWeight (uint32_t  n)   {	int  res = 0 ; 	while  (n) { 		if  (n & 1 ) 			res++; 		n = n >> 1 ; 	} 	return  res; } 
 
 
16.数值的整数次方 
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
 
 
 
输入: 2.00000, 10 输出: 1024.00000
输入: 2.10000, 3 输出: 9.26100
输入: 2.00000, -2 输出: 0.25000 解释: 2-2 = 1/22 = 1/4 = 0.25
dfs————拆分拆分 / 化繁为简 
 
1 2 3 4 5 6 7 8 9 double  myPow (double  x, int  n)   {	if  (n == 0 ) return  1 ; 	if  (n == 1 ) return  x; 	if  (n == -1 ) return  1  / x; 	double  half = myPow(x, n / 2 ); 	double  add = myPow(x, n % 2 ); 	return  half * half*add; } 
 
 
17.打印从1到最大的n位数 
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
 
 
输入: 输入: n = 1 输出: [1,2,3,4,5,6,7,8,9]
 
 
主要考大数问题,用字符串模拟加法 到了这,这题变得毫无意义
 
 
方法:
 
 
 
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 vector <int > res;vector <int > printNumbers (int  n)   {	if  (n <= 0 ) return  res; 	string  number (n, '0' )  ; 	for  (int  i = 0 ; i <= 9 ; i++) { 		number[0 ] = i + '0' ; 		permutionNum(number, n, 1 ); 	} 	return  res; } void  permutionNum (string  &number, int  length, int  index)   {	if  (index == length) { 		saveNum(number); 		return ; 	} 	else  { 		for  (int  i = 0 ; i < 10 ; i++) 		{ 			number[index] = '0'  + i; 			permutionNum(number, length, index + 1 ); 		} 	} } void  saveNum (string  number)   {	string  tempStr (number.size (), '0' )  ; 	std ::cout  << stoi(number) << " " ; 	if  (number != tempStr) 		res.push_back(stoi(number)); } void  bigAdd (string  num1, string  num2, string  &res)   {	int  carry = 0 ; 	int  len1 = num1.length() - 1 ; 	int  len2 = num2.length() - 1 ; 	res = "" ; 	while  (len1 >= 0  || len2 >= 0 ) { 		int  a = len1 >= 0  ? num1[len1--] - '0'  : 0 ; 		int  b = len2 >= 0  ? num2[len2--] - '0'  : 0 ; 		int  tmp = a + b + carry; 		carry = tmp / 10 ; 		res = to_string(long  long (tmp % 10 )) + res; 	} 	if  (carry) { 		res = to_string(long  long (carry)) + res; 	} } 
 
 
18.删除链表的节点 
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
 
 
 
返回删除后的链表的头节点。
输入:
 
 
输入: head = [4,5,1,9], val = 5
 
输出: [4,1,9]
 
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
 
输入: head = [4,5,1,9], val = 1
 
输出: [4,5,9]
 
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
 
方法:
 
 
 
原题剑指1:给定头节点和要删除的节点(快速删除)
删除要删除节点的下一个节点,将下一个节点的值赋给前一个结点 
当最后一个节点为空,还是需要从头遍历 
 
 
原题剑指2:删除链表中的重复节点
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ListNode* deleteNode (ListNode* head, int  val)   {	if  (head == NULL ) 		return  head; 	if  (head->val == val) 		return  head->next; 	 	ListNode* pre = head; 	 	ListNode* temp = NULL ; 	while  (head->next && head) { 		temp = head; 		head = head->next; 		if  (head->val == val) { 			temp->next = head->next; 			break ; 		} 	} 	return  pre; } 
 
 
19.  正则表达式匹配 
请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’ ‘表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”abac a”匹配,但与”aa.a”和”ab*a”均不匹配。
 
 
 
1 2 3 4 5 6 7 8 9 10 bool  isMatch (string  s, string  p)   {	if  (p.empty()) return  s.empty(); 	if  (p[1 ] == '*' ) { 		return  isMatch(s, p.substr(2 )) || (!s.empty() && (s[0 ] == p[0 ] || p[0 ] == '.' )) 			&& isMatch(s.substr(1 ), p); 	} 	else  { 		return  !s.empty() && (s[0 ] == p[0 ] || p[0 ] == '.' ) && (isMatch(s.substr(1 ), p.substr(1 ))); 	} } 
 
 
20.表示数值的字符串 
哈希表 
sort后,进行查找 
 
 
 
21.调整数组顺序使奇数位于偶数前面 
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
 
 
输入:
 
 
输入:nums = [1,2,3,4]
 
输出:[1,3,2,4] 
 
注:[3,1,2,4] 也是正确的答案之一。
 
 
一次快排 
快排需要注意:while右边先写 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 vector <int > exchange (vector <int >& nums)   {	 	if  (nums.size () == 0 ) 		return  {}; 	int  L = 0 ; 	int  R = nums.size () - 1 ; 	while  (L != R) { 		while  (L < R &&nums[L] % 2  == 1 ) 			L++; 		while  (L < R &&nums[R] % 2  == 0 ) 			R--; 		if  (L < R) { 			int  temp = nums[R]; 			nums[R] = nums[L]; 			nums[L] = temp; 		} 	} 	return  nums; } 
 
 
22.链表中倒数第k个节点 
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
 
 
 
vector保存所有结点 
快慢指针,快指针先走K,然后慢指针开始走,sum - k = 要走的步数。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 ListNode* getKthFromEnd (ListNode* head, int  k)   {	ListNode* fast = head; 	ListNode* slow = head; 	while  (k && fast) { 		fast = fast->next; 		k--; 	} 	while  (fast) { 		fast = fast->next; 		slow = slow->next; 	} 	return  slow; } 
 
 
24.反转链表 
1.递归遍历到最后一个节点开始反转
 
 
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 ListNode* reverseList (ListNode* head)   {	if  (head == NULL  || head->next == NULL ) 		return  head; 	ListNode* temp = head->next; 	ListNode* newH = reverseList(temp); 	temp->next = head; 	head->next = NULL ; 	return  newH; } 
 
 
 
 
25.合并两个排序的链表 
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
 
 
输入:
 
 
输入:1->2->4, 1->3->4
 
输出:1->1->2->3->4->4
 
方法:
 
 
 
类似归并排序,归的时候,逐步组成一个有序集合 
 
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 ListNode* mergeTwoLists (ListNode* l1, ListNode* l2)   {	ListNode* pre = NULL ; 	ListNode* head = NULL ; 	if  (l1 == NULL )return  l2; 	if  (l2 == NULL )return  l1; 	if  (l1->val <= l2->val) { 		pre = l1; 		l1 = l1->next; 	} 	else  { 		pre = l2; 		l2 = l2->next; 	} 	head = pre; 	while  (l1&&l2) { 		if  (l1->val <= l2->val) { 			pre->next = l1; 			pre = pre->next; 			l1 = l1->next; 		} 		else  { 			pre->next = l2; 			pre = pre->next; 			l2 = l2->next; 		} 	} 	if  (l1) 		pre->next = l1; 	if  (l2) 		pre->next = l2; 	return  head; }