题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思路:这道题为比较简单的状态转移动态规划题。f(n)=f(n-1)+f(n-2)+f(n-3)....f(1)+f(0);定义一个数组,二层for循环可以得到答案,题目数据量应该不大,数组定义100*int足够。
class Solution {
public:
int jumpFloorII(int number) {
a[0]=1;a[1]=1;
for(int i=2;i<=99;i++)
{
for(int j=0;j<i;j++)
{
a[i]+=a[j];
}
}
return a[number];
}
private:
int a[100]={0};
};
题目描述
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
解题思路:同类型的题目,依然可以是使用斐波那契数列递推求解,f(n)=f(n-1)+f(n-2);因为由f(n-1)到f(n)只有一种放置方法,由f(n-2)不经过f(n-1)直接到f(n)也只有一种放置方法。
class Solution {
public:
int rectCover(int number) {
memset(a,0,sizeof(a));
a[0]=0;a[1]=1;a[2]=2;
for(int i=3;i<=99;i++)
{
a[i]=a[i-1]+a[i-2];
}
return a[number];
}
private:
int a[100];
};
题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
解题思路:利用二进制按位与操作的方式最简便,但是要注意负数按照符号>>右移的时候,高位补充的是1。可以按照<<<右移,这时会忽略高位得补充值,结果也是正确的。还有就是可以自己定义一个flag=1,然后不断左移flag,while的终止条件为flag=0(flag不断左移出了int的范围会重新变为0).
一定要注意按位与操作要加括号!
class Solution {
public:
int NumberOf1(int n) {
int flag =1;int count=0;
while(flag!=0)
{
if((flag&n)!=0)
count++;
flag=flag<<1;
}
return count;
}
};
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
方法一:暴力解法,没什么好说的,直接指数为多少就乘多少次就行。
//暴力解法
class Solution {
public:
double Power(double base, int exponent) {
double res = 1;int x= exponent>0?exponent:-exponent;
if(exponent == 0)
{
return 1;
}
else
{
for(int i=0;i<x;i++)
{
res*=base;
}
}
return exponent>0?res:1/res;
}
};
方法二:
base的exponent可以转换成二进制,即最终的表达也可以用指数为二进制来表示。因为是对exponent的逐位求解, 所以每次将exponent右移一位,同时将需要乘的基准数乘以本身,可以比较简洁且简单地求出一个数的n次幂。
class Solution {
public:
double Power(double base, int exponent) {
double res = 1;
if(exponent == 0)
{
return 1;
}
else
{
int x = exponent>0?exponent:-exponent;
while(x)
{
if(x&1)
{
res*=base;
}
x=x>>1;
base*=base;
}
}
return exponent>0?res:1/res;
}
};
问题:如果遇到非常大的次数,应该是需要用到大数乘法的知识的,不知道这里应该怎么求解呢
题目描述
输入一个链表,输出该链表中倒数第k个结点。
方法一(自己的思路)
遍历两次,第一次先求出整个链表的深度,第二次根据总的深度确定倒数第k个节点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode *tmp = pListHead;
ListNode *res = pListHead;
unsigned int n = 0,i=0;
while(tmp!= NULL)
{
n++;
tmp = tmp->next;
}
tmp = pListHead;
while(tmp!= NULL)
{
if(n-i==k)
{
res= tmp;
break;
}
i++;tmp = tmp->next;
}
if(i==n) return NULL;
return res;
}
};
方法二:
设置两个链表指针,并且两个都指向表头,第一个先走k-1步,然后第二个和第一个一起走,当第一个指针走到头时,则第二个指针所处的位置即为倒数第k个节点。
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode *m = pListHead,*n = pListHead;
int i = 0;
for(;n!=NULL;i++)
{
if(i>=k)
m = m->next;
n = n->next;
}
return i<k?NULL:m;
}
};
题目描述
输入一个链表,反转链表后,输出新链表的表头。
方法:设定三个值分别存储现在的链表节点,下一个链表节点和前一个链表节点,每次将现在的链表节点反指向上一个链表节点,然后将现在的节点赋给上一个节点,下一个节点赋给现在的节点,下一个点的next赋给自身,直循环到下一个结点为NULL为止,然后返回现在的节点即为反转链表的新节点。注意特殊情况的判断。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode *tmp = pHead;
if(pHead == NULL) return NULL;
if(pHead->next == NULL)
{
return pHead;
}
ListNode *cur = pHead->next;
ListNode *next1 = cur->next;
cur->next = tmp; tmp->next = NULL;
while(next1!=NULL)
{
tmp = cur;
cur = next1;
next1 = cur->next;
cur->next = tmp;
}
return cur;
}
};
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
方法一:暴力解法,感觉思路存在问题。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode *fir,*sec;
fir = pHead1;
if(pHead1 == NULL) return pHead2;
if(pHead2 == NULL) return pHead1;
sec = pHead1->next;
ListNode *cur = pHead2,*nex = pHead2->next;
while(sec!=NULL)
{
if(cur->val<=sec->val&&cur->val>=fir->val)
{
fir->next = cur;
cur->next = sec;
fir = sec;
sec = sec->next;
cur = nex;
nex = nex->next;
}
else
{
fir = sec;
sec = sec->next;
}
}
if(cur->val>=fir->val) fir->next=cur;
if(cur->val<=pHead1->val) cur->next
return pHead1;
}
};
方法二:递归
其实利用递归的思想能非常简单地解决这一道题,首先判断return条件,如过第一个链表为空,则返回第二个,如果第二个链表为空,则返回第一个。然后看链表一的第一个元素和链表二的第一个元素谁小,较小的即为这两个链表这中的最小值,它的指向为剩下的值组成的一个新的链表。由此递归思想可以简洁明了的解决这道题目。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL) return pHead2;
else if(pHead2 == NULL) return pHead1;
ListNode *res;
if(pHead1->val<pHead2->val)
{
pHead1->next = Merge(pHead1->next,pHead2);
res = pHead1;
}
else
{
pHead2->next = Merge(pHead1,pHead2->next);
res = pHead2;
}
return res;
}
};
方法三(非递归版本)
采用模拟的方法,定义一个merge后链表的头部mergehead以及一个current指针,然后使用模拟的方法,current指针指向未遍历到的元素中最小的元素,指向下一个次小的元素,具体过程看代码。记得各种边界条件和代码的鲁棒性处理。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL) return pHead2;
if(pHead2 == NULL) return pHead1;
ListNode *current = NULL,*mergehead = NULL;
while(pHead1!=NULL&&pHead2!=NULL)
{
if(pHead1->val<=pHead2->val)
{
if(current == NULL)
{
current = mergehead = pHead1;
}
else
{
current->next = pHead1;
current = current->next;
}
pHead1 = pHead1->next;
}
else
{
if(current == NULL)
{
current = mergehead = pHead2;
}
else
{
current->next = pHead2;
current = current->next;
}
pHead2 = pHead2->next;
}
}
if(pHead1 == NULL) current->next = pHead2;
if(pHead2 == NULL) current->next = pHead1;
return mergehead;
}
};