1、旋转数组的最小数字
题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
我的代码:
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
int len = rotateArray.size();
int min = rotateArray.at(0);
if (rotateArray.empty()==1)
{
return 0;
}
else
{
for (int i = 0; i < len; i++)
{
if (min>=rotateArray.at(i))
{
min = rotateArray.at(i);
}
}
return min;
}
}
};
注意:自己在vs上编译时,调用vector需要加上
#include
using namespace std;
最简洁高效的代码:
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
sort(rotateArray.begin(),rotateArray.end());//进行排序
return rotateArray[0];//返回第一个,即最小值
}
};
2、斐波那契数列的实现
递归方式:
#include
#include
#include
using namespace std;
class Solution {
public:
int Fibonacci(int n) {
if (n == 1 || n == 2)
{
return 1;
}
else
{
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
}
};
int main()
{
Solution a ;
int result = a.Fibonacci(12);
printf("%d", result);
return 0;
}
但递归方式消耗的内存会很大,所以考虑非递归方式:
class Solution {
public:
int Fibonacci(int n) {
int result = 0,first =1,second =1;
if (n == 1 || n == 2)
{
return 1;
}
else
{
for (int i = 3; i <= n; i++)
{
result = first + second;
first = second;
second = result;
}
return result;
}
}
};
3、跳台阶问题
题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
#include
#include
#include
using namespace std;
class Solution {
public:
int jumpFloor(int number) {
int result = 0, first = 1, second = 2;
if (number==0)
return 0;
else if (number == 1)
return 1;
else if (number == 2)
return 2;
else
{
for (int i = 3; i <= number; i++)
{
result = first + second;
first = second;
second = result;
}
return result;
}
}
};
int main()
{
Solution a ;
int result = a.jumpFloor(12);
printf("%d", result);
return 0;
}
4、变态跳台阶问题
5、求输入整数的二进制数中有多少个1
#include
#include
#include
using namespace std;
class Solution {
public:
int NumberOf1(int n) {
int result = 0;
unsigned int flag = 1;
while (flag)
{
if (n&flag)//若求有多少个0,则用n|flag
{
result++;
}
flag=flag << 1;//flag中1的数左移一位,即本来为00000001变为00000010
}
return result;
}
};
int main()
{
Solution a ;
int result = a.NumberOf1(24);
printf("%d", result);
return 0;
}
6、数值的整数次方
题目描述:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
class Solution {
public:
double Power(double base, int exponent) {
double result = 1.0;
if (exponent==0)
return 1;
else if (exponent<0)//也可用abs(exponent)
{
int exp = (-1) * exponent;
for (int j = 0; j < exp; j++)
{
result = result*base;
}
return 1 / result;
}
else
{
for (int i = 1; i <= exponent; i++)
{
result = result*base;
}
return result;
}
}
};
考虑需要全面,当输入的次方为正负和0三种情况。
简单快速幂方法:
class Solution {
public:
double Power(double base, int exponent) {
long long p = abs((long long)exponent);
double r = 1.0;
while(p){
if(p & 1) r *= base;
base *= base;
p >>= 1;
}
return exponent < 0 ? 1/ r : r;
}
};
7、调整数组顺序,使数组中奇数位于偶数前面
题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
class Solution {
public:
void reOrderArray(vector<int> &array) {
int len = array.size();
vector<int> newarray;
if (!array.empty())
{
for (int i = 0; i < len; i++)
{
if (array.at(i)%2)
{
newarray.push_back(array.at(i));//vector容器的函数,表述在vector最后添加一个元素
}
}
for (int i = 0; i < len; i++)
{
if (array.at(i)%2==0)
{
newarray.push_back(array.at(i));
}
}
}
array = newarray;
}
};
8、把字符串转换为整数
题目描述
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
9、最小的k个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int len = input.size();
vector<int> result;
//进行排序,不知道为什么vs中vector没有sort函数,就只能手动排序
for (int i = 0; i < len; i++)
{
int min = input.at(i);
for (int j = i; j < len; j++)
{
if (min >= input.at(j))
{
int temp = min;
min = input[j];
input[i] = min;
input[j] = temp;
}
}
}
if(lenreturn result;
else
{
for (int z = 0; z < k; z++)
{
result.push_back(input[z]);
}
return result;
}
}
};
10、链表的倒序输出
题目描述
输入一个链表,从尾到头打印链表每个节点的值。
思路:用库函数,每次扫描一个节点,将该结点数据存入vector中,如果该节点有下一节点,将下一节点数据直接插入vector最前面,直至遍历完
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> result;
if (head!=NULL)
{
result.insert(result.begin(), head->val);
while (head->next!=NULL)
{
result.insert(result.begin(), head->next->val);
head = head->next;
}
}
return result;
}
};
详细掌握vector
的库函数:重点有insert();begin();end();push_back()
等
11、链表的逆序保存
输入一个链表,反转链表后,输出新链表的表头。
即 0->1->2->3->->5
变成 5->4->3->2->1->0
(0<-1<-2<-3<-4<-5
)
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if (pHead==NULL)
{
return NULL;
}
ListNode* head = pHead;//新建一个链表
pHead = pHead->next;
head->next = NULL;
while (pHead)
{
ListNode* next = pHead->next;
pHead->next = head;
head = pHead;
pHead = next;
}
return head;
}
};
12、两个链表的排序输出
题目描述:
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1==NULL&&pHead2!=NULL)
{
return pHead2;
}
if (pHead1!=NULL&&pHead2==NULL)
{
return pHead1;
}
if (pHead1==NULL&&pHead2==NULL)
{
return NULL;
}
ListNode* result = NULL;
if (pHead1->val<pHead2->val)
{
result = pHead1;
result->next = Merge(pHead1->next, pHead2);
}
else
{
result = pHead2;
result->next = Merge(pHead1, pHead2->next);
}
return result;
}
};
13、二叉树的下一个节点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。(即给定一个二叉树中某一节点,给出改节点的下一个节点)
思路:
(1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B )
(2) 若该节点不存在右子树:这时分两种情况:
2.1 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D )
2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,知道找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 I ,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点)。
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode==NULL)
return NULL;
if(pNode->right!=NULL)
{
pNode = pNode->right;
while(pNode->left!=NULL)
{
pNode=pNode->left;
}
return pNode;
}
while(pNode->next!=NULL)
{
TreeLinkNode* pRoot = pNode->next;
if(pRoot->left==pNode)
{
return pRoot;
}
pNode = pNode->next;
}
return NULL;
}
};
或者更加清晰的逻辑代码为:
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode == null)
return pNode;
if (pNode.right != null) { // 节点有右子树
pNode = pNode.right;
while (pNode.left != null) {
pNode = pNode.left;
}
return pNode;
} else if ( pNode.next != null && pNode.next.left == pNode) { // 节点无右子树且该节点为父节点的左子节点
return pNode.next;
} else if (pNode.next != null && pNode.next .right == pNode) { // 节点无右子树且该节点为父节点的右子节点
while(pNode.next != null && pNode .next .left != pNode){
pNode = pNode.next ;
}
return pNode.next ;
}else{
return pNode.next ;//节点无父节点 ,即节点为根节点
}
}
}
14、数组中只出现一次的数
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
采用异或的方法,看的小鱼很晕,可以一步步调试看结果帮助理解
class Solution {
public:
void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {
if (data.size() < 2) return;
int myxor = 0;
int flag = 1;
for (int i = 0; i < data.size(); ++i)
myxor ^= data[i];
while ((myxor & flag) == 0) flag <<= 1;
*num1 = myxor;
*num2 = myxor;
for (int i = 0; i < data.size(); ++i) {
if ((flag & data[i]) == 0) *num2 ^= data[i];
else *num1 ^= data[i];
}
}
};
小鱼自己的查找方法,比较笨,但是好算好理解
class Solution {
public:
void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {
int len = data.size();
vector<int> result;
for (int i = 0; i < len; i++)
{
int count = 0;
for (int j = 0; j < len; j++)
{
if (i!=j)
{
if (data[i]==data[j])
{
count++;
}
}
}
if (count==0)
{
result.push_back(data[i]);
}
}
*num1 = result.at(0);
*num2 = result.at(1);
}
};
int main()
{
Solution a;
vector<int> data = { 12,12,34,34,24,6 };
int num1, num2;
a.FindNumsAppearOnce(data, &num1, &num2);
cout << num1 << " " << num2;
return 0;
}
15、从上往下打印二叉树
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
思路:借助队列来完成二叉树的遍历
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
vector<int> res;
queue q;
TreeNode* cur;
if (root==NULL)
{
return res;
}
q.push(root);
while (!q.empty())
{
cur = q.front();
res.push_back(cur->val);
if (cur->left!=NULL)
{
q.push(cur->left);
}
if (cur->right != NULL)
{
q.push(cur->right);
}
q.pop();
}
return res;
}
};
16、二叉搜索树的后序遍历
题目说明:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路:二叉搜索树的后序遍历中,最后一个元素为根节点,如果以根节点为基点,可以将数组分成左边全是小与根节点的集合,及数组右边全是大于根节点的集合,则该数组是二叉搜索树的后续遍历结果。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
using namespace std;
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence) {
if (sequence.empty() == 1)
{
return false;
}
int len = sequence.size();
int root = sequence.at(len - 1);
int i = 0, count = 0;
while(root>sequence.at(i))
{
i++;
}
for (int j = i; j < len - 1; j++)
{
if (rootif (count == (len - 1 - i))
{
return true;
}
else
{
return false;
}
}
};
int main()
{
vector<int> a = { 4, 8, 6, 12, 16, 14, 10 };
Solution res;
return res.VerifySquenceOfBST(a);
}
17、求解二叉树的深度
题目说明:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{
if (pRoot==NULL)
{
return 0;
}
else
{
return max(1 + TreeDepth(pRoot->left), 1 + TreeDepth(pRoot->right));
//利用递归,先处理完1 + TreeDepth(pRoot->left)这个递归
//下一个循环变成1+(max(1+TreeDepth(pRoot->left),1+TreeDepth(pRoot->left->right))
//同理就会遍历完所有的情况
}
}
};
18、查找数组中和为sum的两个数
题目说明:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
class Solution {
public:
vector<int> FindNumbersWithSum(vector<int> array, int sum) {
vector<int> res;
if (array.empty()==0)
{
int len = array.size();
int start = 0, end = len - 1;
while (startif (array.at(start)+array.at(end)==sum)
{
res.push_back(array.at(start));
res.push_back(array.at(end));
break;
}
else if (array.at(start) + array.at(end) else
{
end--;
}
}
}
return res;
}
};
注意:题目有一个前提,是数组有序,如果没有该前提,记得在代码中先进行排序(快排),再进行查找(首尾交替),这样时间复杂度会下降。
19、实现数组的快速排序及选择排序
//快速排序
void quickSort(int s[], int l, int r)
{
if (l< r)
{
int i = l, j = r, x = s[l];
while (i < j)
{
while (i < j && s[j] >= x) // 从右向左找第一个小于x的数
j--;
if (i < j)
{
s[i] = s[j];
i++;
}
while (i < j && s[i]< x) // 从左向右找第一个大于等于x的数
i++;
if (i < j)
{
s[j] = s[i];
j--;
}
}
s[i] = x;
quickSort(s, l, i - 1); // 递归调用
quickSort(s, i + 1, r);
}
}
//selectsort选排
void selectSort(int* array)
{
if (array==NULL)
{
return;
}
int len = sizeof(array);
int minIndex;
for (int i = 0; i < len-1; i++)
{
minIndex = i;
for (int j = i+1; j < len-1; j++)
{
if (array[minIndex]>array[j])
{
minIndex = j;
}
}
if (minIndex!=i)
{
swap(array, i, minIndex);
}
}
}
void swap(int* array, int i, int minIndex)
{
int temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
int main()
{
int array[] = { 34,65,12,43,67,5,78,10,3,70 }, k;
int len = sizeof(array) / sizeof(int);
quickSort(array, 0, len - 1);
cout << "The sorted arrayare:" << endl;
for (k = 0; kcout << array[k] << ","<return 0;
}
20、第一次只出现一次的字母
题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1.
小鱼首先想到的是比较笨的方法,就是遍历查找
class Solution {
public:
int FirstNotRepeatingChar(string str) {
int len = str.length();
int i = 0;
while (iint count = 0;
int unique = str[i];
for (int j = 0; j < len; j++)
{
if (unique!=str[j])
{
count++;
}
}
if (count==len-1)
{
return i;
break;
}
else
{
i++;
}
}
return -1;
}
};
这样的查找比较时间复杂度就是O(n2),看完大牛们的评论才想到更简单的方法:
class Solution {
public:
int FirstNotRepeatingChar(string str) {
if(str.size()==0)
return -1;
char ch[256]={0};//A->65,Z->90,a->97,z->122
for(int i=0;i<str.size();i++)
ch[str[i]]++;//这里会将对应的字符转换为ascii码进行存储
for(int i=0;i<str.size();i++)
if(ch[str[i]]==1)
return i;
return 0;
}
};
21、找出超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int len = numbers.size();
int res = numbers.at(0),count=1;
for (int i = 1; i < len; i++)
{
if (res==numbers.at(i))
{
count++;
}
else
{
count--;
}
if (count==0&&i<(len-1))//考虑为奇数的情况,eg:1,2,3,2,4,2,5,2,3
{
res = numbers.at(i);
count = 1;
}
}
if (count>=1)
{
return res;
}
else
{
return 0;
}
}
};
小鱼提示,本题也可用上题思路,开创一片内存,存放每个数字出现的次数。
22、栈的压入、弹出序列
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
#include
#include
using namespace std;
int flag;
class Solution {
public:
bool IsPopOrder(vector<int> pushV, vector<int> popV) {
if (((pushV.empty())&&(!popV.empty())) || (popV.size() != pushV.size()))
return false;
int len = pushV.size(), a = popV.at(0);
if (len==1&&pushV.at(0)!=popV.at(0))
{
return false;
}
//找到出栈的第一个元素在栈中的第几位
for (int i = 0; i < len; i++)
{
if (pushV.at(i)==a)
{
flag=i;
}
}
//出栈的第二位开始,若为前一个出栈的后面或前一位都是合理的
for (int j = 1; j < len; j++)
{
for (int k = 0; k < pushV.size(); k++)
{
if (pushV.at(k)==popV.at(j))
{
if (k>flag)
{
pushV.erase(pushV.begin()+flag);//erase操作之后,size就会变
flag = k-1;//当下一个出栈为前一个出栈的后边,则flag减一
}
else if (k==flag-1)
{
pushV.erase(pushV.begin() + flag);
flag = k ;//当下一个出栈为前一个元素前方,flag不变
}
else
{
return false;
}
}
}
}
return true;
}
};
int main() {
Solution a;
vector<int> pushV = { 1,2,3,4,5 };
vector<int> popV = { 4,5,3,2,1 };
a.IsPopOrder(pushV, popV);
return 0;
}
这是小鱼傻瓜式分析代码
大牛的代码为
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if(pushV.size() == 0) return false;
vector<int> stack;
for(int i = 0,j = 0 ;i < pushV.size();){
stack.push_back(pushV[i++]);
while(j < popV.size() && stack.back() == popV[j]){
stack.pop_back();
j++;
}
}
return stack.empty();
}
};
23、用两个栈来实现队列
题目描述:
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if (stack2.empty())
{
while (!stack1.empty())
{
int a = stack1.top();
stack2.push(a);
stack1.pop();
}
}
int a = stack2.top();
stack2.pop();
return a;
}
private:
stack<int> stack1;
stack<int> stack2;
};
用两个栈实现一个队列的功能?要求给出算法和思路!
<分析>:
入队:将元素进栈A
出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈;
如果不为空,栈B直接出栈。
用两个队列实现一个栈的功能?要求给出算法和思路!
<分析>:
入栈:将元素进队列A
出栈:判断队列A中元素的个数是否为1,如果等于1,则出队列,否则将队列A中的元素 以此出队列并放入队列B,直到队列A中的元素留下一个,然后队列A出队列,再把 队列B中的元素出队列以此放入队列A中。
小鱼会不断更新本文,有问题可以一起讨论,一起加油