1 输入一个链表,反转链表后,输出新链表的表头。
//当前节点是head,pre为当前节点的前一节点,next为当前节点的下一节点
//需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2
//即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了
//所以需要用到pre和next两个节点
//1->2->3->4->5
//1<-2<-3 4->5
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead == NULL) return NULL;
ListNode* pre = NULL;
ListNode* next = NULL;
while(pHead != NULL)
{
next = pHead->next;
pHead->next = pre;
pre = pHead;
pHead = next;
}
return pre;
}
};
2. 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL) return pHead2;
else if(pHead2 == NULL) return pHead1;
if(pHead1->val <= pHead2->val)
{
pHead1->next = Merge(pHead1->next, pHead2);
return pHead1;
}else{
pHead2->next = Merge(pHead1, pHead2->next);
return pHead2;
}
}
};
3.输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
if(!pRoot1)
return false;
if(!pRoot2)
return false;
return ( dfs(pRoot1,pRoot2)) || HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2);
}
bool dfs(TreeNode* pRoot1, TreeNode* pRoot2)
{
if(!pRoot2) return true;
if(!pRoot1) return false; //注意这两句的顺序,先判断pRoot2,再pRoot1
if(pRoot1->val != pRoot2->val) return false;
return (dfs(pRoot1->left, pRoot2->left) && dfs(pRoot1->right, pRoot2->right));
}
};
4. 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
class Solution {
public:
vectorprintMatrix(vector > matrix) {
vectorres;
res.clear();
int row=matrix.size();//行数
int collor=matrix[0].size();//列数
//计算打印的圈数
int circle=((rowfor(int i=0;i //从左向右打印
for(int j=i;jres.push_back(matrix[i][j]);
//从上往下的每一列数据
for(int k=i+1;kres.push_back(matrix[k][collor-1-i]);
//判断是否会重复打印(从右向左的每行数据)
for(int m=collor-i-2;(m>=i)&&(row-i-1!=i);m--)
res.push_back(matrix[row-i-1][m]);
//判断是否会重复打印(从下往上的每一列数据)
for(int n=row-i-2;(n>i)&&(collor-i-1!=i);n--)
res.push_back(matrix[n][i]);
}
return res;
}
};
5. 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
每入栈一次,就与辅助栈顶比较大小,如果小就入栈,如果大就入栈当前的辅助栈顶
当出栈时,辅助栈也要出栈
这种做法可以保证辅助栈顶一定都当前栈的最小值
class Solution {
public:
stackstack1,stack2;
void push(int value) {
stack1.push(value);
if(stack2.empty())
stack2.push(value);
else if(value<=stack2.top())
{
stack2.push(value);
}
}
void pop() {
if(stack1.top()==stack2.top())
stack2.pop();
stack1.pop();
}
int top() {
return stack1.top();
}
int min() {
return stack2.top();
}
};
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
如果有符合条件的数字,则它出现的次数比其他所有数字出现的次数和还要多。
在遍历数组时保存两个值:一是数组中一个数字,一是次数。遍历下一个数字时,若它与之前保存的数字相同,则次数加1,否则次数减1;若次数为0,则保存下一个数字,并将次数置为1。遍历结束后,所保存的数字即为所求。然后再判断它是否符合条件即可。最后的验证 ,防止没有时输出最后一个数字(不满足条件,所以需要最后验证一下)
class Solution {
public:
int MoreThanHalfNum_Solution(vectornumbers) {
int n = numbers.size();
if (n == 0) return 0;
int num = numbers[0], count = 1;
for (int i = 1; i < n; i++) {
if (numbers[i] == num) count++;
else count--;
if (count == 0) {
num = numbers[i];
count = 1;
}
}
// Verifying
count = 0;
for (int i = 0; i < n; i++) {
if (numbers[i] == num) count++;
}
if (count * 2 > n) return num;
return 0;
}
};
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
{
set和multiset会根据特定的排序原则将元素排序。两者不同之处在于,multisets允许元素重复,而set不允许重复。
}
最大堆排序nlog(K)
链接:https://www.nowcoder.com/questionTerminal/6a296eb82cf844ca8539b57c23e6e9bf
来源:牛客网
利用堆排序,O(N logK),适合处理海量数据
(1) 遍历输入数组,将前k个数插入到推中;(利用multiset来做为堆的实现)
(2) 继续从输入数组中读入元素做为待插入整数,并将它与堆中最大值比较:如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,则抛弃这个数,继续读下一个数。
这样动态维护堆中这k个数,以保证它只储存输入数组中的前k个最小的数,最后输出堆即可。
class Solution {
public:
vectorGetLeastNumbers_Solution(vector input, int k) {
vectorresult;
int len = input.size();
if(input.empty() || k<=0 || len < k) return result;
multiset> leastNumbers; // 从大到小排序
multiset>::iterator iterGreater;
vector::iterator iter = input.begin();
for(; iter != input.end(); ++iter)
{
// 将前k个数直接插入进multiset中,注意是小于K
if(leastNumbers.size() < k)
{
leastNumbers.insert(*iter);
}
else
{
// 因为设置的从大到小排序,故multiset中第一个位置的元素即为最大值
iterGreater = leastNumbers.begin();
// 如果input中当前元素比multiset中最大元素小,则替换;即保持multiset中这k个元素是最小的。
if(*iter < *(leastNumbers.begin()))
{
// 替换掉当前最大值
leastNumbers.erase(iterGreater);
leastNumbers.insert(*iter);
}
}
}
for(iterGreater = leastNumbers.begin();iterGreater!=leastNumbers.end();++iterGreater)
{
result.push_back(*iterGreater); // 将multiset中这k个元素输出
}
return result;
}
};
https://www.cnblogs.com/ChinaHook/p/6985518.html
https://www.cnblogs.com/ChinaHook/p/6985444.html
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
使用动态规划
F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变
F(i)=max(F(i-1)+array[i] , array[i])
res:所有子数组的和的最大值
res=max(res,F(i))
如数组[6, -3, -2, 7, -15, 1, 2, 2]
初始状态:
F(0)=6
res=6
i=1:
F(1)=max(F(0)-3,-3)=max(6-3,3)=3
res=max(F(1),res)=max(3,6)=6
i=2:
F(2)=max(F(1)-2,-2)=max(3-2,-2)=1
res=max(F(2),res)=max(1,6)=6
i=3:
F(3)=max(F(2)+7,7)=max(1+7,7)=8
res=max(F(2),res)=max(8,6)=8
i=4:
F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7
res=max(F(4),res)=max(-7,8)=8
以此类推
最终res的值为8
class Solution {
public:
int FindGreatestSumOfSubArray(vectorarray) {
if(array.empty()) return 0;
int sum = array[0], tempsum = array[0]; //注意初始值 不能设为0 防止只有负数
for(int i = 1; i < array.size(); i++) //从1开始 因为0的情况在初始化时完成了
{
tempsum = (tempsum < 0) ? array[i] : tempsum + array[i];
sum = (tempsum > sum) ? tempsum : sum;
}
return sum;
}
};
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
回溯法
class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
vectorflags(rows*cols,0);
bool condition=false;
for(int i=0;ifor(int j=0;j {
if(isPath(matrix,flags,str,i,j,rows,cols) )
return true;
}
return false;
}
bool isPath(char *matrix,vectorflags,char* str,int x,int y,int rows, int cols)
{
if(x<0 || x>=rows || y<0 || y>=cols) //越界的点
return false;
if( matrix[x*cols+y]== *str && flags[x*cols+y]==0 )
{
flags[x*cols+y]=1;
if(*(str+1)==0) // 字符串结尾了(最后一个满足的)
return true;
bool condition =isPath(matrix,flags,(str+1),x,y-1,rows,cols) ||
isPath(matrix,flags,(str+1),x-1,y,rows,cols)||
isPath(matrix,flags,(str+1),x,y+1,rows,cols)||
isPath(matrix,flags,(str+1),x+1,y,rows,cols);
if(condition == false)
flags[x*cols+y]=0;
return condition;
}
else
return false;
}};
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
回溯法
class Solution {
public:
int movingCount(int threshold, int rows, int cols)
{
bool *flag = new bool[rows * cols];
for(int i = 0; i < rows * cols; i++)
flag[i] = false;
int count=moving(threshold,rows,cols,0,0,flag);//从(0,0)坐标开始访问;
delete[] flag;
return count;
}
int moving(int threshold,int rows,int cols,int i,int j,bool* flag)
{
int count=0;
if(check(threshold,rows,cols,i,j,flag))
{
flag[i*cols+j]=true;
//标记访问过,这个标志flag不需要回溯,因为只要被访问过即可。
//因为如果能访问,访问过会加1.不能访问,也会标记下访问过。
count=1+moving(threshold,rows,cols,i-1,j,flag)
+moving(threshold,rows,cols,i,j-1,flag)
+moving(threshold,rows,cols,i+1,j,flag)
+moving(threshold,rows,cols,i,j+1,flag);
}
return count;
}
//检查当前位置是否可以访问
bool check(int threshold,int rows,int cols,int i,int j,bool* flag)
{
if(i>=0 && i=0 && j && getSum(i)+getSum(j)<=threshold
&& flag[i*cols+j]==false)
return true;
return false;
}
//计算位置的数值
int getSum(int number)
{
int sum=0;
while(number>0)
{
sum+=number%10;
number/=10;
}
return sum;
}
};
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
//deque s中存储的是num的下标
class
Solution {
public
:
vector<
int
> maxInWindows(
const
vector<
int
>& num, unsigned
int
size)
{
vector<
int
> res;
deque<
int
> s;
for
(unsigned
int
i=0;i
while
(s.size() && num[s.back()]<=num[i])
//从后面依次弹出队列中比当前num值小的元素,同时也能保证队列首元素为当前窗口最大值下标
s.pop_back();
while
(s.size() && i-s.front()+1>size)
//当当前窗口移出队首元素所在的位置,即队首元素坐标对应的num不在窗口中,需要弹出
s.pop_front();
s.push_back(i);
//把每次滑动的num下标加入队列
if
(size&&i+1>=size)
//当滑动窗口首地址i大于等于size时才开始写入窗口最大值
res.push_back(num[s.front()]);
}
return
res;
}
};
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
class Solution {
public:
priority_queue, less > small;
priority_queue, greater > big;
void Insert(int num)
{
if(small.empty() || num<=small.top())
small.push(num);
else
big.push(num);
if(small.size() == big.size() +2)
{
big.push(small.top());
small.pop();
}
if(small.size() +1 == big.size())
{
small.push(big.top());
big.pop();
}
}double GetMedian()
{
return small.size() == big.size() ? (small.top() + big.top()) / 2.0 : small.top();
}};
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
//思路:二叉搜索树按照中序遍历的顺序打印出来正好就是排序好的顺序。
// 所以,按照中序遍历顺序找到第k个结点就是结果。
class Solution {
public:
int count = 0;
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(pRoot)
{
TreeNode *ret = KthNode(pRoot->left, k);
if(ret) return ret;
if(++count == k) return pRoot;
ret = KthNode(pRoot->right, k);
if(ret) return ret;
}
return nullptr;
}
};
请实现两个函数,分别用来序列化和反序列化二叉树
class Solution {
public:
vectorbuf;
void dfs1(TreeNode *root) {
if(!root) buf.push_back(-1); //-1=0xFFFFFFFF
else {
buf.push_back(root->val);
dfs1(root->left);
dfs1(root->right);
}
}
TreeNode* dfs2(int* &p) {
if(*p==0xFFFFFFFF) {
p++;
return NULL;
}
TreeNode* res=new TreeNode(*p);
p++;
res->left=dfs2(p);
res->right=dfs2(p);
return res;
}
char* Serialize(TreeNode *root) {
buf.clear();
dfs1(root);
int bufSize=buf.size();
int *res=new int[bufSize];
for(int i=0;ireturn (char*)res;
}
TreeNode* Deserialize(char *str) {
int *p=(int*)str;
return dfs2(p);
}
};
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
class Solution {
public:
vector> Print(TreeNode* pRoot) {
vector> vec;
if(pRoot == NULL) return vec;
queueq;
q.push(pRoot);
while(!q.empty())
{
int min = 0;
int max = q.size();
vectortmp;
while(minTreeNode* cur = q.front();
q.pop();
tmp.push_back(cur->val);
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
min++;
}
vec.push_back(tmp);
}
return vec;
}
};
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
class Solution {
public:
vector> Print(TreeNode* pRoot) {
vector> res;
if(pRoot == NULL) return res;vector
q;
q.push_back(pRoot);
bool model = true;
while(!q.empty())
{
int min = 0;
int max = q.size();
vectortmp;
vectorrow;
tmp = q;
q.clear();
while(minTreeNode* cur = tmp.back();
tmp.pop_back();
row.push_back(cur->val);
if(!model)
{
if(cur->right) q.push_back(cur->right);
if(cur->left) q.push_back(cur->left);
}else{
if(cur->left) q.push_back(cur->left);
if(cur->right) q.push_back(cur->right);
}
min++;
}
model = !model;
res.push_back(row);
}
return res;
}
};