原 剑指offer(刷题11-20)--c++,Python版本

该博客围绕《剑指offer》中第11 - 20题展开,涵盖求浮点数次方、调整数组数字顺序、链表操作、二叉树判断与变换、矩阵打印、栈操作等题目。针对每题给出解题思路,如使用栈、递归等方法,并提供C++和Python代码实现及运行时间、占用内存情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

第11题:

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

解题思路:

  • 这道题非常简单,但是存在陷阱,即当exponent为负数和0的时候要特别考虑,其余的没有了

代码实现:

c++
#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

 double Power(double base, int exponent) {
	 double temp = base;
	 if(exponent < 0 ){
		 for(int i =1 ;i<-(exponent);i++){
			temp *= base;
		 }
		 return 1.0/temp;
	 }else if(exponent ==0){
		return 1;
	 }else{
		for(int i = 1 ; i<exponent ; i++){
			temp *= base;
		}
		 return temp;
	 }
 }

int main(){
	cout<<Power(2,-3)<<endl;
	cout<<Power(2,0)<<endl;
	cout<<Power(2,2)<<endl;
	return 0;
}

运行时间:5ms

占用内存:456k

python
# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        return base**exponent

运行时间:22ms
占用内存:5624k

第12题:

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

解题思路:

  • 通过使用2个栈结果来保存奇数项和偶数项,然后对数组从后向前遍历,遇到奇数就压奇数栈,遇到偶数就压偶数栈,然后在依次弹出奇数栈和偶数栈中的内容,并保存在原始的数组中(先将原始数组清空)

代码实现:

c++
#include <stack>
class Solution {
public:
    void reOrderArray(vector<int> &array) {
       stack<int> oddStack;//定义奇数栈
        stack<int> evenStack;//定义偶数栈
        for(int i = array.size()-1 ; i >= 0 ;i--){
            if(array[i] % 2 == 0){
                evenStack.push(array[i]);
            }else{
                oddStack.push(array[i]);
            }
        }
        array.clear();
        while(!oddStack.empty()){
            array.push_back(oddStack.top());
            oddStack.pop();
        }
        while(!evenStack.empty()){
            array.push_back(evenStack.top());
            evenStack.pop();
        } 
    }
};

运行时间:5ms

占用内存:480k

python
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        oddList = []  #保存奇数
        evenList = []  #保存偶数
        for i in array:
            if i % 2 == 0:
                evenList.append(i)
            else:
                oddList.append(i)
        array = []
        for i in oddList:
            array.append(i)
        for i in evenList:
            array.append(i)
        return array

运行时间:23ms

占用内存:5724k

第13 题:

输入一个链表,输出该链表中倒数第k个结点。

解题思路:

  • 首先顺序遍历一遍链表,并将值压栈,然后在通过栈弹出第K个元素即为链表的倒数第K个元素。时间复杂度为O(n),空间复杂度为O(n);

代码实现:

c++
/*
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<ListNode*> tempStack;
	    if(pListHead == NULL){
		    return NULL;
	    }
	    if(k <= 0){
		    return NULL;
	    }
	    int dataCount = 0;
	    while (pListHead != NULL){
		    tempStack.push(pListHead);
		    pListHead = pListHead->next;
		    dataCount++;
	    }
	    if(dataCount < k){
		    return NULL;
	    }
	    for(int i = 0 ; i < k - 1 ; i++){
		    tempStack.pop();
	    }
	    return tempStack.top();
    }
};

运行时间:4ms

占用内存:476k

python
# -*- coding:utf-8 -*-
class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        res=[]
        while head:
            res.append(head)
            head=head.next
        if k>len(res) or k<1:
            return
        return res[-k]

运行时间:26ms
占用内存:5732k

第 14题:

输入一个链表,反转链表后,输出新链表的表头。

解题思路:

  • 本体的意思应该是输出原始链表的反转链表,而不是仅仅只是输出反转后链表的头结点,所以通过栈的结构实现不佳。思想是:从头到尾遍历链表,然后将每两个节点进行反转操作即可,最好将原始的头结点的后继置NULL,头结点直接取最后一个元素

代码实现:

c++
class Solution {
public:
    ListNode* ReverseList(ListNode* pListHead) {
       if(pListHead == NULL)
		return NULL;
	ListNode *pCurrent ,*pPre,*pNext;
	                              //一、指针的初始化阶段
	pPre = pListHead;
	pCurrent = pPre->next ;
 
	while(pCurrent)               //二、反转单链表的核心代码
	{
		pNext = pCurrent->next ;   //1. 缓冲pCurrent后面的单链表
		pCurrent->next = pPre ;	   //2. 反转单链表
		pPre = pCurrent;           //3.让pPre指针后移
		pCurrent = pNext ;         //4. 让pCurrent指针后移
	}
					   //三、处理并返回头指针
	pListHead->next = NULL;                //把原头结点的next域变成空指针
	pListHead = pPre ;		           //把头结点指向最后一个结点产生新的头结点,也就是把原单链表的尾结点变成头结点
 
	return pListHead;
    }
};

运行时间:5ms

占用内存:464k

python
# -*- coding:utf-8 -*-

第15 题:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

解题思路:

  • 递归的方法:依次在链表1和链表2遍历,每次取两个链表中较小的那个值插入到新的链表中去。

代码实现:

c++
递归实现
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == NULL && pHead2 == NULL){
		    return NULL;
	    }
	    if(pHead1 == NULL){
		    return pHead2;
	    }
	    if(pHead2 == NULL){
		    return pHead1;
	    }
	    ListNode* head;  //新链表的表头
	    if(pHead1->val < pHead2->val){
		    head = pHead1;
		    head->next =  Merge(pHead1->next , pHead2); //递归调用
	    }else{
		    head = pHead2;
		    head->next =  Merge(pHead1, pHead2->next);
	    }
	    return head;
    }
};

运行时间:4ms

占用内存:492k

python
# -*- coding:utf-8 -*-

第16 题:

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

解题思路:

  • 找一颗树是否为另外一颗树的子树,当然是遍历主树,先从根节点开始,如果根节点相同,就比较左右孩子节点,如果相同,则返回true,否则就递归遍历主树的左子树和右子树,只要找到一个相同即可。在比较子树和主树之前,我们要定义一个函数用于比较两个二叉树是否相同。也是从根节点开始,依次对比根节点,左孩子,右孩子是否相同,只有全部节点相同才是相同。

代码实现:

c++
class Solution {
public:
    
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(!pRoot1 || !pRoot2) return false;
        bool result=false;
        if(pRoot1->val == pRoot2->val)result=isSubtree(pRoot1,pRoot2); // 找到判断子树
        if(!result) result=HasSubtree(pRoot1->left,pRoot2); // 未找到匹配的根节点以及匹配的子树,则继续向下递归
        if(!result) result=HasSubtree(pRoot1->right,pRoot2);
        return result;
    }
   //判断2棵树是否相同
  bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
   {
       if(!pRoot2) return true; // 子树遍历完成(关键语句)
       if(!pRoot1) return false; // 主树异常时的输出(关键语句:提高鲁棒性)
       bool result=true;
       if(pRoot1->val!=pRoot2->val) result=false; //根节点不同肯定不同
       if(result) result=isSubtree(pRoot1->left,pRoot2->left); //判断两颗树的左子树是否相同
       if(result) result=isSubtree(pRoot1->right,pRoot2->right);//判断两颗树的右子树是否相同
       return result;
   }
};

运行时间:3ms

占用内存:504k

python
# -*- coding:utf-8 -*-

第17题:

操作给定的二叉树,将其变换为源二叉树的镜像。

解题思路:

从题目中给出的例子可以看出,其实就是对树的每一层中双亲的左右孩子交换了一下。我们可以递归的访问树的每一层,然后交换每一层的双亲节点的左右孩子就可以。

  • 递归的方法:先从根节点开始,交换根节点左右孩子节点,然后调用递归,依次遍历树的左子树和右子树,交换子树中的孩子节点。

代码实现:

c++
递归实现
class Solution {
public:
    void Mirror(TreeNode *pRoot) {
		//递归推出条件
        if(pRoot==NULL){
            return;
        }
        //交换根节点的两个孩子
        TreeNode* tempNode;
        tempNode = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = tempNode;
        Mirror(pRoot->left);  //递归左子树
        Mirror(pRoot->right); //递归右子树
    }
};

运行时间:4ms

占用内存:468k

python
# -*- coding:utf-8 -*-
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if root == None:
            return ;
        tempNode = TreeNode(-1)
        tempNode = root.left
        root.left = root.right
        root.right = tempNode
        self.Mirror(root.left)
        self.Mirror(root.right)

运行时间:34ms

占用内存:5736k

第18题:

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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.

解题思路:

  • 设定四个变量,分别指向行,列的起始点和终止点,然后将数据遍历分成4个节阶段,分别是:从左到右,从上到下,从右向左,从下到上,每个过程结束后,对应的指针都应该变化,循环执行,直到遍历完全部的数据。

代码实现:

c++
class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int>res;  //用来保存遍历过的数据
        res.clear(); 
        int row=matrix.size();//行数
        int collor=matrix[0].size();//列数
        //计算打印的圈数
        int circle=((row<collor?row:collor)-1)/2+1;//圈数
        for(int i=0;i<circle;i++){
            //从左向右打印
            for(int j=i;j<collor-i;j++)
                res.push_back(matrix[i][j]);         
            //从上往下的每一列数据
            for(int k=i+1;k<row-i;k++)
                res.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;

    }
};

运行时间:4ms

占用内存:468k

python
# -*- coding:utf-8 -*-

第19题:

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))

解题思路:

  • 定义一个辅助栈,这个栈顶元素始终是最小值。

代码实现:

c++
class Solution {
public:
     
    stack<int> stack1,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();
    }
     
};

运行时间:2ms

占用内存:472k

python
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.data = []
        self.minData = []

    def push(self, node):
        # write code here
        self.data.append(node)
        if self.minData == [] or node < self.minData[-1]:
            self.minData.append(node)
            
    def pop(self):
        # write code here
        if self.data[-1] == self.minData[-1]:
            self.minData.pop()
        self.data.pop()
    def top(self):
        # write code here
        return self.data[-1]
    def min(self):
        # write code here
        return self.minData[-1]

运行时间:31ms

占用内存:5624k

第20 题:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

解题思路:

借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。

举例:

入栈1,2,3,4,5

出栈4,5,3,2,1

首先1入辅助栈,此时栈顶1≠4,继续入栈2

此时栈顶2≠4,继续入栈3

此时栈顶3≠4,继续入栈4

此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3

此时栈顶3≠5,继续入栈5

此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3

….

依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序

代码实现:

c++
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();
    }
};

运行时间:3ms

占用内存:380k

python
# -*- coding:utf-8 -*-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值