主题:
日常刷算法题,今天涉及到的有:
- 虚表的实际存储方式和内容规则
- 算法题:矩阵的最小路径问题(动态规划实现)
- 算法题:判断有没有环
- 算法题:用栈来实现队列操作,以及优化
内容:
1 矩阵的最小路径问题(动态规划问题)
问题:给定一个 n * m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,
路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
基本思路:
思路1:动态规划的状态转换:假设现在处于一个矩阵的元素上,这个元素对应位置
上的到右下角的最小路径应该是 这个点的值+min(右边的点的最小路径,下面的点的最小路径)
因此可以使用一个数组dp来对应于矩阵的每一个位置的元素,记录每一个对应的元素
的到达右下角的最小路径,然后输出dp[0][0]即可。需要用到递归
思路2:也是动态规划的状态转换,只是每一个dp对应的元素表示的是从左上角走到这个
元素的最小路径。最后输出dp[n-1][m-1]即可。想要做出这个dp,可以考虑,第一行只可以来
自左边,第一列只可以来自上面。dp[0][0]是一个定值。
dp值 = 这个点的值+min(左边的点的最小路径,上面的点的最小路径)
代码:
int solve(int i,int j) //递归实现的
{
return dp[i][j] = matrix[i][j]+ i>=row||j>=collumn?0:min(solve(dp[i+1][j]),solve(dp[i],[j+1]); )
}
int minPathSum(vector<vector<int> >& matrix) {
// write code here
int collumn = matrix[0].size();
int row = matrix.size();
int dp[row][collumn];
memset(dp, 0, sizeof(dp));
dp[0][0] = matrix[0][0];
for(int i=1;i<row;i++)
{
dp[i][0] = matrix[i][0]+dp[i-1][0];
}
for(int i=1;i<collumn;i++)
{
dp[0][i] = matrix[0][i]+dp[0][i-1];
}
for(int i=1;i<row;i++)
{
for(int j=1;j<collumn;j++)
{
dp[i][j] = matrix[i][j]+min(dp[i-1][j], dp[i][j-1]);
}
}
return dp[row-1][collumn-1];
}
2 判断有没有环的问题:
**问题:**判断给定的链表中是否有环。如果有环则返回true,否则返回false。你能给出空间复杂度的解法么?
**解题思路:**当打一个结来作为来过的标记,当检测到这个结的时候,说明来过,发生了环
bool hasCycle(ListNode *head) {
ListNode* p = head;
ListNode* temp;
while(1)
{
if(p==NULL)
{
return false;
}
else{
if(p==p->next)
{
return true;
}
else{
temp = p;
p = p->next;
temp->next = temp;
}
}
}
}
3 两个栈来实现一个队列
基本思路:当push的时候,就在一个栈里面进行push就可
当pop的时候,需要将一个栈的内容腾到另外一个栈里面,然后pop,就会pop出原来最
后面的元素。再腾到第一个栈里面
优化思路:惰性优化:当pop后,先不急着腾到另外一个栈,如果下一个还是pop
那么直接pop就行。如果下一个不是pop,再进行腾。因此,再push的时候需要判断
如果是第二个栈有元素,说明处于惰性状态,进行转移,然后push,否则,直接push
当pop的时候,如果第二个栈有元素,直接pop,如果没有元素,转移,然后pop
void push(int node) {
stack1.push(node);
}
int pop() {
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
int tem = stack2.top();
stack2.pop();
while(!stack2.empty())
{
stack1.push(stack2.top());
stack2.pop();
}
return tem;
}
private:
stack<int> stack1;
stack<int> stack2;
};
4 虚表的实际存储方式
表指针(如果有条件存在的话)会存在于堆或者栈,和数据成员存放在一起
虚表的内容存放于代码段之上,虚函数则存放于代码段。
当继承时,子类的虚函数 如果是重写了父类的虚函数的话,那么就会覆盖虚表中的条目
当没有重写父类的虚函数时,会加在虚表的后面。
继承时子类和父类都会有非虚函数,不会出现在虚表中,这些函数的调用会根据指针的对象类型来调用.当调用对象为父类的指针/引用/对象名 的时候,只可以看见父类的内容。不管其理论上可不可以访问。此时会编译器报错。
代码:
class A
{
public:
virtual int fun()
{
return 1;
}
void show1()
{
cout<<"show1\n";
}
};
class B:public A
{
public:
virtual void show2()
{
cout<<"show2\n";
}
};
int main(){
A a;
cout<<sizeof(A)<<endl; //输出8
a.show1();
B b;
b.show2();
A* ap = new B;
//ap->show2(); //此时会出错,因为指针类型可以理解为“视角”,在A的视角上,看不见B的内容
//编译器报错,即使把
B* bp = new B;
bp->show1(); //
bp->show2(); //都不会报错,因为B的视角更大,可以看见A的内容
return 0;
}