剑指offer之2/6

1 数值的整数次方
需要考虑的点
当底数为0,指数为负的情况下,此时数字无意义,所以要进行异常保护
其他指数为负的时候,应该取绝对值然后算结果。
第二种方法,可以使用公式,利用递归的方式求解。

2 打印从1到n的最大n位数
考虑大数问题,使用字符串表示数字,这块的代码不懂。。。
第二种方法是转化成全排列问题,n个从0到9的全排列,使用递归的方式。

void print1tomax(int n)
{
   if(n<=0)
   return;
   char* number=new char[n+1]; ///创建一个字符数组
   number[n]='\0';
   for(int i=0;i<10;i++)
   {
      number[0]='0'+i; ///最高位
      print(number,n,0);
   }
   delect[] number;
 }

 void print(char* number ,int n, int index)
 {
     if(index==n-1)
     {
        printnumber(number);
        return;
      }
     for(int i=0;i<10;i++)
     {
        number[index+1]=i+'0';
        print(number,n,index+1);
        }
   }

void printnumber( char* number)
{
  bool isbeginning0=true;
  int length=strlen(number);
  for(int i=0;i<length;i++)
  {
     if(isbeginning0&&number[i]!='0')
       isbeginning0=false;  ///找到第一个不是零的数位
        if(!beginning0)     
        printf("%c",number[i]);
  }
  printf("\t);
}


3.删除链表节点(要求时间复杂度为O(1))
思路:把要删除的节点的下一个结点赋给当前要删的节点,覆盖原来的内容,再把这个下一结点删除,这样就相当于删除了当前需要删除的节点了。
但是如果要删除的是尾结点时,仍需遍历整个链表,才能进行删除。

4.删除链表中重复的节点
应该定义三个指针,第一个指针指向出现重复结点的前一个结点(用于与后面重新连接)第二个指针指向第一个重复结点,第三个指针指向最后一个重复结点。删除的过程就是第一个指针->next=第三个指针->next;

5.正则表达式匹配
思路:第一种情况,模式中第二个字符不是*,那就正常进行匹配,如果字符串和模式的对应字符相等,两者都进行移动一个字符继续进行比较。
第二种情况,模式中第二个字符是 ,这时前面的字符可以是任意个,这时有两种匹配方法,一种是模式跳两个字符(等于忽略了前面的字符),第二种是模式不动,字符串不断和模式做匹配(等于说是*前面有很多个一样的字符供匹配)

6.表示数值的字符串
思路:把字符串分成三个部分。一是整数部分,首先判断有没有±号,如果有,跳到下一字符,从这个字符开始,如果他是一个数字字符,跳下一个,如果他不是,终止。
二判断小数部分,三判断指数部分

class Solution {
public:
    bool isNumeric(const char* string)
    {
        if(string==nullptr)
            return false;
        bool isnum=scanInteger(&string);
        if(*string=='.')
        {
            ++string;
            isnum=scanUnsignedInteger(&string)||isnum;
            //上面两判断,位置不能换,因为如果第一个为true,第二个就不运行了,指针就不会增加,卡到这,*string就不会等于'\0'.返回的就是错误的false
        }
        if(*string == 'e' || *string == 'E')
        {
          ++string;
 
        // 下面一行代码用&&的原因:
        // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;
        // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4
          isnum = isnum && scanInteger(&string);
         }
        return isnum&&*string=='\0'; ///这里第二个条件很关键,保证遍历了字符串,如果没有,12+3.3E5+2,这种也会被判为true,因为指针到12就不走了。事实上只要指针中途不走,字符串肯定就不是数值
    }
 
bool scanUnsignedInteger(const char** str)
{
    const char* before = *str;
    while(**str != '\0' && **str >= '0' && **str <= '9')
        ++(*str);
 
    // 当str中存在若干0-9的数字时,返回true
    return *str > before;
}
 
// 整数的格式可以用[+|-]B表示, 其中B为无符号整数
bool scanInteger(const char** str)
{
    if(**str == '+' || **str == '-')
        ++(*str);
    return scanUnsignedInteger(str);
}
};


7.调整数组顺序使奇数位于偶数前
思路:遍历数组,找出所有奇数,放在一个容器内,再遍历一遍找出所有偶数,放在一个容器内,把两个容器相接。
第二种思路是利用类似于冒泡排序的方法,两两比较,交换位置

8.链表中倒数第K个结点(倒数第k个结点和尾结点相差k-1步)
思路:定义两个指针,第一个指针先走k-1步,第二个指针再开始走,两个指针以同样的速度行进,当第一个指针到最后一个结点时,指针二指的的就是第K个结点。
需要注意的是异常保护,k=0,头指针为空,链表总长度小于K的情况需加以保护

9.链表中环的入口结点
思路:首先,找到位于环中的一个节点,定义两个指针,一个指针每次走两步,另一个指针每次走一步,走的快的指针追上走的慢的指针的时候,相遇节点就是环中结点。

其次,计算出环中有多少个结点,从上一步算出的环中结点开始,每次走一步,当再次到达该节点时,就可以计算出环中有多少个结点

最后,定义两个指针指向链表的头结点,一个指针先走n步,然后两个指针以相同的速度向前移动,当两个指针相遇时,该点就是入口结点,(第一个指针已经绕环走了一圈了)

10.反转链表
使用栈来反转

11.合并两个排序的链表
思路:逐位比较,小的翻前面,大的放后面,,典型的用递归求解

12.树的子结构
思路:第一步,在数A中查找与根节点的值一样的节点,如果相等,判断根节点的左右字树,和B数根节点的左右字树是不是相等,直到B树被遍历完,返回true。 如果根节点不相等,那就找A的左右子树种找有没有跟B数根节点相等的点。

bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool result=false;
        if(pRoot1!=nullptr&&pRoot2!=nullptr)
        {
            if(pRoot1->val==pRoot2->val) ///先找相等的根节点,找到之后进行左右子数判断
                   result=dosetree1hastree2(pRoot1,pRoot2);
            if(!result) ///
                   result=HasSubtree(pRoot1->left,pRoot2); ///在左子数中不断找根节点相等
            if(!result)
                   result=HasSubtree(pRoot1->right,pRoot2);///在右子树中不断找根节点相等      
        }
           return result;
      }
    
    bool dosetree1hastree2(TreeNode* pRoot1, TreeNode* pRoot2)
        {
            if(pRoot2==nullptr) //终止条件
                return true;
            if(pRoot1==nullptr)
                return false;
            if(pRoot1->val!=pRoot2->val)
               return false;
             return dosetree1hastree2(pRoot1->left,pRoot2->left)&&
                    dosetree1hastree2(pRoot1->right,pRoot2->right);
         }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值