从尾到头打印链表
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
思路
- 栈的先进后出特性
代码
/** * struct ListNode { * int val; * struct ListNode *next; * ListNode(int x) : * val(x), next(NULL) { * } * }; */ class Solution { public: vector<int> printListFromTailToHead(ListNode* head) { vector<int> v; stack<int> s; while( head != NULL ){ //将链表元素按顺序压入栈 s.push(head->val); head = head->next; } while( !s.empty() ){ //将栈中元素从尾到头弹出 v.push_back( s.top() ); s.pop(); } return v; } };
重建二叉树
- 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
- 思路
- 递归
- 将序列分为根节点的左子树与右子树
- 将左子树的序列分为其根节点的左子树与右子树
- 将右子树的序列分为其根节点的左子树与右子树
- 直至叶子节点
- 递归
预备知识
- 前序遍历:当前节点->左子树->右子树
- 28 16 13 22 30 29 42
- 特性:第一个节点一定为根节点,根节点->左部->右部
- 中序遍历:左子树->当前节点->右子树
- 13 16 22 28 29 30 42
- 特性:左部->根节点->右部
- 后序遍历:左子树->右子树->当前节点
- 13 22 16 29 42 30 28
- 特性:左部->右部->根节点
- 前序遍历:当前节点->左子树->右子树
代码
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { int len = pre.size(); if( len == 0 ) return NULL; vector<int> leftPre, leftVin; //存放位于二叉树左边的节点 vector<int> rightPre, rightVin; //存放位于二叉树右边的节点 TreeNode* head = new TreeNode(pre[0]); //前序遍历的第一个数一定是根节点 //找到中序遍历中根节点的位置,存储在temp变量中 int temp = 0; for( int i = 0; i < len; i++ ){ if( vin[i] == pre[0] ){ temp = i; break; } } for( int i = 0; i < temp; i++ ){ leftPre.push_back(pre[i+1]); leftVin.push_back(vin[i]); } for( int i = temp+1; i < pre.size(); i++){ rightPre.push_back(pre[i]); rightVin.push_back(vin[i]); } head->left = reConstructBinaryTree(leftPre, leftVin); head->right = reConstructBinaryTree(rightPre, rightVin); return head; } };
旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路
- 近乎有序,特点是左区间的元素大小均大于等于右 区间
- 目的是找到右区间的最左元素
- 中间元素比最后一个元素大,表明其位于左区间
- 中间元素比最后一个元素小,表明其位于右区间
- 中间元素等于最后一个元素,无法区分,但是表明最右元素不是最小值,可减去
代码
# -*- coding:utf-8 -*- class Solution: def minNumberInRotateArray(self, rotateArray): # write code here left = 0 right = len(rotateArray) - 1 #没有元素 if right == -1: return 0 #一个元素直接返回 if right == 0: return rotateArray[0] while left <= right: #防止整形越界 mid = left + (right -left)/2 if rotateArray[mid] > rotateArray[right]: left = mid + 1 elif rotateArray[mid] < rotateArray[right]: right = mid else: right -= 1 if left >= right: break return rotateArray[left]
跳台阶
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路
- 设f(n)为跳法数
- f(0) = 0
- f(1) = 1
- f(2) = 1
- 在最后一次跳台阶,有两种可能
- 跳1级台阶,则跳法数由f(n-1)决定
- 跳2级台阶,则跳法数由f(n-2)决定
- 综上,跳上一个n级的台阶所有可能的跳法f(n) = f(n-1) + f(n-2)
- 这是个斐波那契数列
代码
# -*- coding:utf-8 -*- class Solution: def jumpFloor(self, number): # write code here if number == 0: return 0 if number == 1: return 1 if number ==2: return 2 count , first , second = 0 , 1 , 2 for i in range(3 , number + 1): count = first + second first = second second = count return count
变态跳台阶
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
- 思路
- 设f(n)为跳法数
- f(0) = 0
- f(1) = 1
- 在最后一次跳台阶,有n种可能
- 跳1级台阶,则跳法数由f(n-1)决定
- 跳2级台阶,则跳法数由f(n-2)决定
- …
- 跳n级台阶,则跳法数由f(n-n)决定
- 综上,f(n) = f(n-1) + f(n-2) +…+f(n-n)····a
- f(n-1) = f(n-2) + f(n-3) +…+f(n-n)·····b
- a-b 得到 f(n) = 2 * f(n-1)
代码
# -*- coding:utf-8 -*- class Solution: def jumpFloorII(self, number): # write code here if number == 0: return 0 if number == 1: return 1 count = 1 for i in range(2 , number + 1): count = 2 * count return count