数组查找
(1)二维数组中的查找
题目描述
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
解题思路
考虑到二维数组是从左到右递增,从上到下递增.因此对每一行i,从右上角j=array[i].size-1(下标值是数组行大小-1)开始比较,若数组当前值array[i][j]比target大,那么target值只能是在后面的行(i++);若array[i][j]<target,那么target可能在当前行,往前面列查找(j--);相等返回.
想法和LeetCode_TwoSum是不是很像呢!
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int i=0,r = array.size(),j=array[0].size()-1;
while(i<r&&j>=0)
{
if(array[i][j]>target) j--;
else if(array[i][j]==target) return 1;
else i++;
}
return 0;
}
};
# -*- coding:utf-8 -*-
class Solution:
# array 二维列表
def Find(self, target, array):
# write code here
i=0
r = len(array)
j = len(array[0]) - 1
while(i<r and j>=0):
if(target<array[i][j]):
j=j-1
elif(target==array[i][j]):
return 1
else: i=i+1
return 0
(c++: && Python:and;Matlab:&)扎心了
(2)替换空格(指针的使用)
题目描述
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
char* str="hello world ";这个指针指向常量字符串,存储在静态存储区,是只读的,不能被修改。
而char str[]="hello world"是一个局部变量数组,存储在栈上的内存空间,可以被修改。
class Solution {
public:
void replaceSpace(char *str,int length) {
char *p,*end;
p=str;
int Len=0,newLen = 0,space=0;
while(*p!='\0')
{
if (*p==' ')
space++;
Len ++;
p++;
}
newLen = Len + space*2;
end = str + newLen ;
*end = '\0';
end--;
p = str + Len - 1;
while(p>=str)
{
if(*p!=' ')
*end-- = *p;
else
{
*end--='0';
*end--='2';
*end--='%';
}
p--;
}
}
};
解题思路:
char *str ,字符串数组,将空格替换成'%20',替换增加了两个字符,需要将空格后的字符往后挪到.先统计所有空格的个数,计算字符串的新长度.设了新的指针end指向新长度的末尾.p指向原字符串末尾,从最后开始挪动到end指向的位置.
(3)链表的使用
题目描述
输入一个链表,从尾到头打印链表每个节点的值。
解题思路:
a.遍历链表,值存到堆栈.最后将堆栈存的值top给vector
b.递归,总感觉把递归想得很复杂,写不出来,看了别人答案写出来的....
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
stack <int> stk;
vector<int> a;
while(head!=NULL)
{
stk.push(head->val);//入栈
head = head->next;
}
while(!stk.empty())
{
a.push_back(stk.top());//取值
stk.pop();//出栈
}
return a;
}
};
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> a;
if(head!=NULL){
if(head->next!=NULL){
a=printListFromTailToHead(head->next);
}
a.push_back(head->val);
}
return a;
}
};
(4)重构二叉树
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
解题思路
前序第一个元素就是该树的根节点,创建根节点;
中序根节点左边的节点就是该树的左子树的所有节点(n个)的中序列表(前序列表就是根节点后n个),递归构建该左子树;
同理右子树可建.
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.empty()||vin.empty())
return NULL;
if(pre.size()!=vin.size())
return NULL;
int vlen=vin.size();
int i,ind,leftLen=0,rightLen=0;
for(i=0;i<vlen;i++)
if(vin[i]==pre[0]){
ind = i;
break;
}
else leftLen++;
rightLen = vlen -leftLen -1;
vector<int> left_pre,left_vin,right_pre,right_vin;
for(i=0;i<ind;i++){//分别提取左右子树的前序,中序
left_vin.push_back(vin[i]);
left_pre.push_back(pre[i+1]);
}
for(i=ind+1;i<vlen;i++){
right_vin.push_back(vin[i]);
right_pre.push_back(pre[i]);
}
TreeNode* T=new TreeNode(pre[0]);//创建节点
if(leftLen>0)
T->left= reConstructBinaryTree(left_pre,left_vin);
else T->left = NULL;
if(rightLen>0)
T->right=reConstructBinaryTree(right_pre,right_vin);
else
T->right = NULL;
return T;
}
};
(5)栈&队列
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
解题思路
用两个模拟队列,s1主要用来入队列,s2用来出队列;
当s2为空时,从s1出栈(后进s1的先出到s2的栈底)到s2的元素满足先进先出.
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
int t=-1;
if(!stack2.empty())
{
t = stack2.top();
stack2.pop();
}
else if(!stack1.empty())
{
while(!stack1.empty()){
stack2.push(stack1.top());
stack1.pop();
}
t = stack2.top();
stack2.pop();
}
return t;
}
private:
stack<int> stack1;
stack<int> stack2;
};
(6)查找和排序
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解题思路
二分查找.但是因为该数组是非递减数组的一个旋转,也就是在两个递增序列的临界处不满足递增性质.这边代码的处理,感觉和生硬..mid直接是后面的那个元素的下标.
class Solution {
public:
int minNumberInRotateArray(vector<int> array) {
int len = array.size();
int start=0,mid=0,end=len-1;
if(len==0)
return 0;
while(start<=end)
{
mid = (start+end)/2;
if(start==end-1){
mid=start+1;
break;
}
if(array[start]<=array[mid])
{
start = mid;
}
else
end = mid;
}
return array[mid];
}
};
(7)斐波那契数列(递归和循环)
题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39
class Solution {
public:
int Fibonacci(int n) {
if(n==0)
return 0;
if(n==1)
return 1;
int i,N,N1,N2;
N1 = 0;
N2 = 1;
for(i=2;i<=n;i++)
{
N = N1+N2;
N1 = N2;
N2 = N;
}
return N;
//RE:return Fibonacci(n-1)+Fibonacci(n-2); // F(n)=F(n-1)+F(n-2)
}
};
(8)跳台阶(递归和循环)
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思路
类似(7)的做法,递归!
跳n阶的时候,选择跳1阶或者2阶,那么相应就是(n-1)和(n-2)阶的时候:f(n)=f(n-1)+f(n-2)
bug:有先后顺序,比如1,2和2,1是不一样的跳法
class Solution {
public:
int jumpFloor(int n) {
int x=0,y=(n+1)/2,sum=0;
for(x=0;x<=n;x++)
{
if(n==x+2*y)
sum++;
else if(n<x+2*y)
y--;
}
return sum;
}
};
class Solution {
public:
int jumpFloor(int n) {
if(n==1)
return 1;
if(n==2)
return 2;
int i,N,N1=1,N2=2;
for(i=3;i<=n;i++)
{
N=N1+N2;
N1=N2;
N2=N;
}
return N;
}
};
(9)变态跳台阶(递归和循环)
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思路:
f(n) = f(n-1) +...+f(1)+f(0) ; f(1)=1,f(0)=1,展开计算会发现,其实f(n)=2^(n-1)
class Solution {
public:
int jumpFloorII(int n) {
int i=0,N=0,N1=1;
if(n==1)
return 1;
/*for(i=1;i<=n;i++)//f(n)=f(n-1)+...f(1)+f(0)
{
N=N+N1;
N1=N;
}
return N;//3ms
*/
return pow(2,n-1);//3ms,424k
}
};
(10) 矩形的覆盖(递归和循环)
题目描述
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
解题思路
敲重点!(记住这是考递归和循环)小矩形无非是横着放(就相当于还要覆盖2*(n-1)的矩形)或竖着放(必须放两个小矩形,就相当于还要覆盖2*(n-2)的矩形)
class Solution {
public:
int rectCover(int n) {
int i=0,N1=1,N2=2,N;
if(n<=2)
return n;
for(i=3;i<=n;i++)
{
N = N1+N2;
N1 = N2;
N2 = N;
}
return N;
}
};
(11)二进制数中1的个数
题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
解题思路
(参考:http://blog.csdn.net/gogogo_sky/article/details/71550423)
主要考察的是位位运算,五种位运算有:
(1)&(与)–有0则0;无0则1;
(2)|(或)–有1则1,无1则0;
(3)^(亦或)–相同为0,不同为1;
(4)>>右移(最右边的位被抛弃)
正数,最左边添0;00001010>>3=00000001
负数,最左边添1;10001010>>3=11110001
(5)<<左移(最左边的位被抛弃)–最右边统一添0;
(正数)00001010<<3=01010000
(负数)10001010<<3=01010000
2.求一个 数二进制中1的个数:
class Solution {
public:
int NumberOf1(int n) {
int N=n,sum=0;
while(N)
{
sum++;
N=N&(N-1);
}
return sum;
}
};
(12)数值的整数次方
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
解题思路:
要做的很直接,考察代码的完备性.考虑exp以及base的特殊值.
对于求n次方,也可以先求n/2在平方
class Solution {
public: //3ms,392k
double Power(double base, int exponent) {
if(base==0)
return 0.0;
if(exponent==0)
return 1.0;
else if(exponent==1)
return base;
// a^n = a^(n/2)*a(n/2) (odd) *a
int exp=abs(exponent);
double p = Power(base,exp>>1);//a^(n/2)
p *= p;
if(exp&0x1)//odd exp
p=p*base;
if(exponent<0)
p=1.0/p;
return p;
}
/*//4ms,492k
double Power(double base, int exponent) {
int flag = exponent%2,exp=abs(exponent);//1 odd,0 even
double p = 1;
if(base==0)
return 0.0;
if(exponent==0)
return 1.0;
else if(exponent==1)
return base;
while(exp>0)
{
p = base * p;
exp -- ;
}
if(exponent<0)
p = 1.0 / p;
return p;
}*/
};
(13)调整数组中奇数和偶数的顺序
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
解题思路:
考虑当前位置i的元素为奇数还是偶数,为奇数则继续遍历下个元素(更新当前数组中第一个奇数的位置j);为偶数,寻找之后数组中的第一个奇数位置j,并把i到j之间的偶数往后挪动,替换i位置的偶数为寻找到的奇数(array[j]被覆盖之间先保存下来).j主要作用就是指向要开始寻找奇数的位置,不用重复遍历数组.
class Solution {
public: //2ms,480k
void reOrderArray(vector<int> &array) {
int i,j=1,k,tmp,len = array.size();
for(i=0;i<(len-1)&&j<len;i++)
{
if(array[i]%2)//odd
{
j=i+1;
continue;
}
while((array[j]%2==0)&&j<len)//find first odd
j++;
if(j==len)
break;
if(array[j]%2)//move even number backward,replace even num in array[i] with odd number array[j]
{
tmp = array[j];
for(k=j;k>i;k--)
{
array[k]=array[k-1];
}
array[i] = tmp;
}
}
}
};
(14) 链表的倒数第K个
题目描述
输入一个链表,输出该链表中倒数第k个结点。
解题思路
首先判断链表为空和倒数K个节点不存在的情况.
设置两个指针遍历链表,第一个指针先走k-1个节点,第二个指针开始走;
当第一个指针指向最后一个节点的时候,第二个节点指向倒数第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) {
//stack<int> stack1;
int len=0,i,ck=0;
ListNode* cur;
ListNode* pTail = pListHead;
if(pListHead==NULL||k==0)
return NULL;
/*
while(pTail!=NULL) // 额外遍历一次链表得到长度,浪费时间
{
len++;
pTail = pTail->next;
}
if(len<k)
return NULL;// to short
pTail = pListHead;
while(pListHead!=NULL&&ck<k)
{
ck ++;
pListHead = pListHead->next;
}
*/
for(ck=0;ck<k;ck++)//在头指针往前走k-1次的时候就判断,链表长度是否大于k
{
if(pListHead!=NULL)
{
pListHead = pListHead->next;
}
else
return NULL;
}
while(pListHead)
{
pTail = pTail->next;
pListHead = pListHead->next;
}
return pTail;
}
};
(15)反转链表
题目描述
输入一个链表,反转链表后,输出链表的所有元素。
解题思路
首先排除链表为空或者只有一个节点的情况.
指针遍历链表的时候,反转每个节点的next指向.设置pre,cur,nex分别指向遍历时候的前一个指针,当前指针,以及下一个指针.主要是在反转的时候,注意不要断链,也就是丢失nex.
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* pre=pHead;
ListNode *nex=pHead,*cur=pHead;
if(pHead==NULL|| pHead->next==NULL)
return pHead;
while(cur)
{
nex = cur->next;
cur->next = pre;
pre = cur;
cur = nex;
}
pHead->next = NULL;
return pre;
}
};
(16)合并有序链表
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
解题思路
首先考虑存在某个链表为空的情况;
当链表都不空的情况下,假设最小元素在链表1的第一个节点,此时相当于将链表2的元素逐个按序插入链表1;pre,cur1指向遍历链表1时候的前一个元素和当前元素;cur2,nex指向遍历链表2的当前元素和下一个元素.cur1指向元素小于cur2指向元素,则链表1的指向元素分别往后遍历;cur1指向元素大于cur2指向元素,则首先记录链表2的下一个遍历元素nex,修改cur2元素指向cur1,pre的下个元素指向cur元素,即完成cur2元素插入到链表1.
最后需判断是链表1先遍历完还是链表2,将pre的下个元素指向其余元素,完成全部元素的合并.
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode *cur1=pHead1,*cur2=pHead2,*nex=pHead2,*pre=pHead1;
if(pHead1==NULL || pHead2==NULL)
return pHead1 != NULL ? pHead1:pHead2;
if(cur2->val<cur1->val)
{
int tmp = cur1->val;
cur1->val = cur2->val;
cur2->val = tmp;
}
while(cur1 && cur2)
{
if(cur1->val<=cur2->val)
{
pre = cur1;
cur1 = cur1->next;
}
else
{
nex = cur2->next;
cur2->next = cur1;
pre->next = cur2;
cur2=nex;
}
}
pre->next = cur1==NULL?cur2:cur1;
return pHead1;
}
};
(17)树的子结构
题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
解题思路
首先考虑树为空的情况;
当两棵树都非空的情况下,判断以当前根节点pRoot1为子树的结构与pRoot2为子树的结构是否相同?不同再递归判断pRoot1左右子树是否存在与pRoot2树结构相同?
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
if(pRoot1&&pRoot2)//判断以当前根节点pRoot1为子树的结构与pRoot2为子树的结构是否相同?不同再递归判断pRoot1左右子树是否存在与pRoot2树结构相同?
return SameTree(pRoot1,pRoot2)||HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);
else
return false;
}
bool SameTree(TreeNode* pRoot1,TreeNode* pRoot2)
{
if(pRoot2==NULL)
return true;
if(pRoot1==NULL||pRoot1->val!=pRoot2->val)
return false;
return SameTree(pRoot1->left,pRoot2->left)&&SameTree(pRoot1->right,pRoot2->right);
}
};
(18) 二叉树的镜像
题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
解题思路
(1)递归实现:镜像二叉树,就是交换左右子树.先交换当前节点的左右子树指针,再递归镜像操作左右子树.
(2)非递归实现:借助栈,保存当前子树的根节点,每次取出一个节点(一棵子树)交换左右子树.
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
TreeNode *tmp = pRoot->left;
if(pRoot)
{
pRoot->left = pRoot->right ;
pRoot->right = tmp;
Mirror(pRoot->left);//递归交换左右子树
Mirror(pRoot->right);
}
}
};
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot==NULL)
return;
stack<TreeNode*> s;//非递归,借助栈保存树节点
s.push(pRoot);
while(!s.empty())
{
TreeNode *cur = s.top();
s.pop();
TreeNode *tmp = cur->left;
cur->left = cur->right;
cur->right = tmp;
if(cur->left)
s.push(cur->left);
if(cur->right)
s.push(cur->right);
}
}
};
(19)顺时针打印矩阵
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
int sc=0,sr=0,ec=matrix[0].size()-1,er=matrix.size()-1;
vector<int> a;
while(sc<=ec&&sr<=er)
{
int curc=sc,curr=sr;
if(sr==er)
{
while(curc<=ec){ //只有一行
a.push_back(matrix[sr][curc++]);
}
}
else if(sc==ec)
{
while(curr<=er)//只有一列
a.push_back(matrix[curr++][sc]);
}
else
{
while(curc<ec)//从左到右
a.push_back(matrix[sr][curc++]);
while(curr<er)//从上到下
a.push_back(matrix[curr++][ec]);
while(curc>sc)//从右到左
a.push_back(matrix[er][curc--]);
while(curr>sr)//从下到上
a.push_back(matrix[curr--][sc]);
}
sc++;
sr++;
ec--;
er--;
}
return a;
}
};
(20)包含 min 函数的栈
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
stack<int> s;
stack<int> min_val; //记录当前深度的栈, 对应的最小值
void push(int value) {
s.push(value);
//调整 最小值的 栈
if(min_val.empty()||min_val.top()>value)
min_val.push(value);
else if(min_val.top()<value)
{
int tmp=min_val.top();
min_val.push(tmp);
}
}
void pop() {
if(!s.empty())
{
s.pop();
min_val.pop();
}
}
int top() {
return s.top();
}
int min() {
return min_val.top();
}
(21)栈的压入、弹出序列
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if(pushV.size()!=popV.size())
return false;
if(pushV.size()==0)
return true;
stack<int> s;
int i=0,j=0;
while(pushV[i]!=popV[j])
s.push(pushV[i++]); //元素入栈,直到第一个出栈元素
while(!s.empty())
{
if(s.top()==popV[j])
{
//cout<<s.top()<<endl;
s.pop();
j++;
}
else if(i<pushV.size())
{
s.push(pushV[i++]);
}
else
break; //退出条件,输入序列已经在栈内,并且栈顶元素不是输出序列元素
}
if(s.empty())
return true;
else
return false;
}
(28) 数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
int MoreThanHalfNum_Solution(vector<int> numbers) {
if(numbers.empty())
return 0;
int i,val=numbers[0],num=0,count=0;
for(i=0;i<numbers.size();i++)
{
if(num==0)
val = numbers[i]; //不相同数字相互抵消
if(numbers[i]==val)
num++;
else
num--;
}
//cout<<val<<endl;
for(i=0;i<numbers.size();i++) //最后留下的数字,判断出现次数 是否 超过一半
{
if(val==numbers[i])
count++;
}
if(count<=numbers.size()/2)
return 0;
else
return val;
}
(29)最小的K个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路:
降序排序,使用冒泡,只需K次即可
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int i=0,j=0,key=0,n=input.size();
vector<int> arr;
if(k>n||input.empty())
return arr;
for(i=0;i<k;i++)
{
for(j=i+1;j<n;j++)
{
if(input[j]>input[j-1])
//冒泡排序,相邻两个数进行比较,每次最小值冒泡到最底部位置
{
key = input[j-1];
input[j-1]=input[j];
input[j]=key;
}
}
arr.push_back(input[n-i-1]);
}
return arr;
}
(30)连续子数组的最大和
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:
1)两重 for 循环,O(N*N)
2)线性时间算法
该算法在每次元素累加和小于0时,从下一个元素重新开始累加
int FindGreatestSumOfSubArray(vector<int> array) { //两重循环 O(n*n)
int i,j,max,n=array.size(),sum;
if(array.empty())
return -1;
max = array[0];
for(i=0;i<n;i++)
{
sum = array[i];
for(j=i+1;j<n;j++)
{
sum+=array[j];
if(sum<0)
{
//cout<<array[i]<<','<<array[j]<<endl;
sum-=array[j];
break;
}
if(max<sum)
{
max = sum;
}
}
//cout<<array[i]<<"->"<<array[j]<<endl;
if(max<sum) //数组全部为负数的情况?
{
max = sum;
}
}
return max;
}
int FindGreatestSumOfSubArray_On(vector<int> array) { //O(n)
int i,j,max,n=array.size(),sum=0;
max = array[0];
for(i=0;i<n;i++)
{
sum +=array[i];
if(max<sum)
max = sum;
if(sum<0) //当前累加和小于0,则从下一个元素开始考虑连续子数组的和
sum=0;
}
return max;
}
(31) 整数中1出现的次数(从1到n)
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。\
思路:
1) 穷举,对区间内的每个数都判断,包含1的个数(复杂度为O(logn)) -- 整体复杂度为 O(nlogn)
2)O(logn) https://blog.csdn.net/yi_afly/article/details/52012593
int hasOne(int n)
{
int i,sum=0;
int k,v;
while(n)
{
v = n%10;
if(v==1)
sum++;
n = n/10;
}
return sum;
}
int NumberOf1Between1AndN_Solution(int n)
{
int i,sum=0;
for(i=1;i<=n;i++)
{
int num =hasOne(i);
sum += num;
// cout<<num<<endl;
}
return sum;
}
int NumberOf1Between1AndN_Solution(int n)
{
int round=n,weight,base=1,count=0;
while(round)
{
weight = round%10; //参考博客介绍,数学规律,对数字的各个位上 ,分析1出现的次数
round /=10;
count +=round*base;
if(weight==1)
count+=(n%base)+1;
else if(weight>1)
count+=base;
base *= 10;
}
return count;
}
(32)把数组排成最小的数
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:
1)排序算法,主要是重新定义这里的cmp。数字/字符 ab>ba,则认为b<a
// AC code,别人过的代码,调用了sort和to_string,我本地不能通过
string PrintMinNumber(vector<int> numbers) {
int len = numbers.size();
if(len == 0) return "";
sort(numbers.begin(), numbers.end(), cmp);
string res;
for(int i = 0; i < len; i++){
res += to_string(numbers[i]);
}
return res;
}
static bool cmp(int a, int b){
string A = to_string(a) + to_string(b);
string B = to_string(b) + to_string(a);
return A < B;
}
(33) 丑数
题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:
1) 暴力求解,从1开始,对每个数判断是不是丑数(while(n) n/=2; while(n) n/=3; while(n) n/=5; ),累计到N个丑数
2)提前计算,
丑数:2^i * 3^j *5^k
利用额外的数组,判断当前可能的丑数中(之前的丑数 *2或*3或*5得到的数),最小的加入到数组内
//第二种解法
int min(int a,int b,int c)
{
int m = (a<b)?a:b;
return m<c?m:c;
}
int GetUglyNumber_Solution(int index) {
int i,j,num=1;
vector<int> ugly;
ugly.push_back(1);
int p2,p3,p5;
p2=p3=p5=0;
while(ugly.size()<index)
{
int min_u = min(ugly[p2] *2,ugly[p3]*3,ugly[p5]*5);
ugly.push_back(min_u);
if(ugly[p2]*2<=min_u)
p2++;
if(ugly[p3]*3<=min_u)
p3++;
if(ugly[p5]*5<=min_u)
p5++;
}
return ugly[index-1];
}
(34)第一个只出现一次的字符
题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)
思路:
1) 所有字母包括 a-z,A-Z
设置 flag表示该字母出现的次数,index记录该字母出现的首次位置
遍历字符串,查找,flag为1,index最小的返回
int FirstNotRepeatingChar(string str) {
int i,min=str.size();
if(str.size()==0)
return -1;
int flag[52]={0},index[52]={0},ind;
for(i=0;i<str.size();i++)
{
char cur = str[i];
if(cur>='a'&&cur<='z')
ind = cur-'a';
else if(cur>='A'&&cur<='Z')
ind = cur-'A'+26;
if(flag[ind]==0)
index[ind] = i;
flag[ind]++;
}
for(i=0;i<52;i++)
{
cout<<i<<','<<flag[i]<<','<<index[i]<<endl;
if(flag[i]==1)
{
if(index[i]<min)
min = index[i];
}
}
if(min==str.size())
return -1;
else
return min;
}
(35)数组中的逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
输入:
1,2,3,4,5,6,7,0
输出:
7
思路:
1)可以借助归并排序,计算逆序对的个数,这边是从尾部开始合并,方便计算逆序对个数
long long InversePairsCore(vector<int> &data,vector<int> ®,int start,int end)
{
int k=end,mid = (start+end)/2;
if(start==end)
return 0;
long long cnt=0;
cnt+=InversePairsCore(data,reg,start,mid);
cnt+=InversePairsCore(data,reg,mid+1,end);
//cnt+=Merge(data,reg,start,end);
int start1=start,end1=mid,start2=mid+1,end2=end;
while(start1<=end1&&start2<=end2)
{
if(data[end1]>data[end2])
{
cnt+=end2-mid; //!! 从后往前 计算 逆序的个数,因为 左右数组分别有序, 左边最大的数 大于 右边最大的数, 逆序的pair个数为 end2-(mid+1) -1 = end2-mid
reg[k--]=data[end1--];
}
else
reg[k--]=data[end2--];
}
while(start1<=end1)
reg[k--]=data[end1--];
while(start2<=end2)
reg[k--]= data[end2--];
for(k=start;k<=end;k++)
data[k]=reg[k];
return cnt;
}
int InversePairs(vector<int> data) {//形参data,不会 将改变的值 传递回main函数
int cnt=0,i;
int start = 0,end = data.size()-1;
if(start<end)
{
vector<int> reg;
for(i=0;i<data.size();i++)
reg.push_back(data[i]);
cnt =InversePairsCore(data,reg,0,data.size()-1)%1000000007;
}
return cnt;
}