首页 > 其他分享 >剑指offer

剑指offer

时间:2023-07-13 20:12:27浏览次数:59  
标签:map 遍历 return cur 递归 offer int

《剑指Offer》读书笔记。感谢强哥给的书。希望明年的我也可以Offer满满~

代码基本都在这里了:https://github.com/ixsim/OJ

Problems

  • class A{
    	static A getInstance();
        void func();
    private:
        A();
        A(A& rth);
        ~A();
    };
    A A::getInstance(){
        static A a;
        return a;
    }
    
  • if(p->left||p->right){
    	swap(p->left,p->right);
    }//这样就不行
    //这样就可以
    if(p->left||p->right){
        TreeNode *temp = p->left;
        p->left = p->right;
        p->right = temp;
    }
    

    看上去一样。但其实 swap两个指针。在里面操作半天。回来p的左右孩子还是没变化。

Notes

  • 在C/C++中,数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。
  • 需要倒着再干啥的考虑【栈】
  • 很多需要快速找到最大值或最小值的问题都可以用【堆】来解决
  • 由于精度原因不能用等号判断两个小数是否相等。如果两个小数差的绝对值很小,就可以认为他们相等
  • 我们有成熟的O(N)算法得到数组中任意第k大的数字
  • 采用值传递,形参到实参会产生一次复制操作
  • 题目描述一棵树--> 是不是二叉树 --> 是不是排序树

第二章 基础知识

3搜索二维数组

  • 牛客的没AC。先LeetCode上找了74搜索二维矩阵,这个稍微简单点,用一个二分查找就可以。然后240题搜索二维矩阵II就是一样的了。

  • 看书知道了要删减的思路后。就从右上角开始。先排除的列,又排除的行。然后继续用最笨的方法去查找(其实也是一步步排除行和列的过程)。没有考虑到:

    排除 列 和 行 的过程可以同时进行,直到循环结束啊。

  • PS:我之前这种思路是错误的:

    类似二分查找,先找到要搜的列,再从这一列用二分查找。这样其实有的元素存在,但并不在你要找的这一列。

4替换空格

5尾到头打印链表

用栈比较easy了.但是递归的写法注意:

//我的写法:
while(node->next!=nullptr){function递归(a,b);}
//1.递归不能用while 要用if 啊
//2.不能只看是不是最后一个节点。还要看当前节点:
if(node!=null){
    if(node!=nullptr){
        func();
    }
}

6重建二叉树

确定递归思路后一口气撸下来,⌘ + R , 测试没问题 。提交OJ。PASS。这一周看书最爽的一次AC。

7用两个栈实现队列

虽然自己写AC了。但是方案不如书上。

我是借助stack2进行pop, 每次pop完再回传给stack1。

其实不需要的。好好考虑考虑吧!

8 旋转数组的min

看似水题。但遍历一次要O(N)

二分查找可以边O(logN)。然后还要考虑特殊情况。不可轻视

int minNumberInRotateArray(vector<int> v) {
    int n = v.size();
    int l = 0, r = n-1;
    int m = l;
    while(v[l]>=v[r]){
        if(r-l==1){
            m = r;
            break;
         }
        int m = (l+r)>>1;
        if(v[m]>=v[l])
            l = m;
        if(v[m]<=v[r])
            r = m;
    }
    return v[m];
}

9 斐波那契

除了普通法和递归法,要注意还有O(logN)的解法。

10 二进制中1的个数

位运算。

  • 1不停地执行左移。执行到首位(符号位)不就成了负的?然后再左移不就永远成了负的?

    ANS: 左移不会保留符号位。右移才保留

  • 位运算效率远高于乘除。尽可能得用位运算代替乘除。

第三章 高质量代码

11 快速幂

马马虎虎地过了,看了书后发现,我并没有考虑底数是特殊值的情况。(只分了指数的情况)

Note:

  • 用全局变量的方式抛出异常。

12 打印1到n位最大数

不能用int型。要用string型。

13 O(1)时间内删除链表节点

题目思路简单。注意这种情况:

  • 只有一个节点,要删除这个节点。

14 调整数组顺序

判断奇数偶数这回我知道用位运算了。但是请注意这个Warn:

  • & has lower precedence than ==; 等号运算符的优先级高于&!所以要用位运算判断的与或非 记得加括号

15 链表中倒数第k个节点

  • 我这个二傻子。把节点一个个存到栈里。然后出栈到第k个。AC了。

    为啥不存到vector里然后用下标就能返回倒数第k个呢。

  • 书上的方法,用两个指针,两个相距k,当一个走到尾的时候,另个就是答案了。

16 反转链表

先用了栈做。龙哥刚好过来。让我自己想想别用栈。我一想。哈哈。挺简单。

17 合并有序链表

我用循环写的。比较简单。Note:

18 判断是不是树的子结构

我最后AC的版本存在本地了。有这么个错误代码需要注意:

bool HasSubtree(TreeNode* p1, TreeNode* p2){
    if(p1==nullptr||p2==nullptr)
        return false;
    if(p1->val==p2->val)
    {   
        if(isSame(p1,p2))
            return true;
        else {
            if(p1->left)
                HasSubtree(p1->left,p2); 
            if(p1->right)
                HasSubtree(p1->right,p2);
        }
    }
    return false;
}

问题出现在第10行。我的想法是,如果有左子树就去走左子树。但是Debug的时候我发现,就算走到了第7行的return true, 程序也不会返回true的。因为我的第10行根本没有返回啊。只是去走一走。返回的一个true是从栈里返回到了第10行,并没有从第10行返回给main啊。

PS:这题牛客的测试用例绝对不全。

&&的短路特性

/*求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句.
解:利用&&的短路特性:如a&&b即如果a为假,b则被短路(不运算)
*/int add_fun(intn)                  
{   int num=0;
    (n>0)&&(num=n+add_fun(n-1));     
    return num;       
} 
int main( ) 
{ 
    intsum=0; 
    intn=100;  
    printf("%d\n",add_fun(n)); 
    return0; 
} 

第四章 解决思路

19 二叉树的镜像

easy 秒过

20 顺时针打印

思路清晰。一次撸过。下次看看自己怎么写的就好啦。

不要二刷。

21最小栈

easy不多说

22入栈出栈次序

知道了用辅助栈的思路。比较好写。

不过,我没仔细看书上的代码。有空还是好好看一看。

23二叉树层序遍历

层序遍历就用队列嘛。easy。

24判断是不是后序遍历序列

没思路。看书吧!

看书知道了思路。过了。其中输入数组为空的情况没考虑。细心点!

25路径选择

应该是深度优先搜索。但我最近脑子不转,写递归的思路老是抽。

老是想,这个节点遍历完往回退的时候,怎么减到当前的节点。

其实在循环的最后一步把栈给POP一下就行了

26复杂链表的复制

我的思路还是很清晰的。用一个map存。Key是原链表的地址,Value是新链表的地址。这样就有了一一对应关系。看代码:

RandomListNode* Clone(RandomListNode* pHead)
{
    RandomListNode *ans = new RandomListNode(-1);
    RandomListNode *cur = ans;

    map<RandomListNode *,RandomListNode *> map;

    while(pHead!=nullptr){

        if(map.find(pHead)!=map.end()){//如果有就不new了
            cur->next = map[pHead];
            cur = cur->next;
        }else{//没有就new了 并存到map里
            RandomListNode *tmp = new RandomListNode(pHead->label);
            map[pHead] = tmp;
            cur->next = tmp;
            cur = cur->next;
        }

        if(pHead->random){
            //寻找 map 中有没有 pHead的random
            if(map.find(pHead->random)!=map.end()){//如果有就指向
                cur->random = map[pHead->random];
            }else{//没有就new了并存到map里
                RandomListNode *tmp = new RandomListNode(pHead->random->label);
                map[pHead->random] = tmp;
                cur->random = tmp;
            }
        }
        pHead = pHead->next;

    }
    
    return ans->next;
}
  • 注意第20行的if(pHead->random) 之前一直过不了正是由于有的节点没有random指针,为空时自然取不到label值。以后写的时候要思考全面。

27 二叉树与双向链表

先中序遍历,存到栈里。

然后再设置左右子树就很简单了。

思路好想,关键是输入为null的特殊情况我一直没处理。导致过不了。

  •     TreeNode* Convert(TreeNode* pRootOfTree)
        {
            if(pRootOfTree == nullptr) return nullptr;
            TreeNode* pre = nullptr;
             
            convertHelper(pRootOfTree, pre);
             
            TreeNode* res = pRootOfTree;
            while(res ->left)
                res = res ->left;
            return res;
        }
         
        void convertHelper(TreeNode* cur, TreeNode*& pre)
        {
            if(cur == nullptr) return;
             
            convertHelper(cur ->left, pre);
             
            cur ->left = pre;
            if(pre) pre ->right = cur;
            pre = cur;
             
            convertHelper(cur ->right, pre);
             
             
             
        }
    

28 字符串的排列

全排列嘛。我知道要用递归写。可是就是钻进了牛角尖。一时间想不出来递归的参数怎么设置。

  • multiset是允许key相同的set
  • 输入的string 为“”时,要特判!

第五章 时间空间效率

29 绝对众数

  • 之前刷LeetCode知道有摩尔投票法了。做起来很轻松。

    当然这题不一样的就是,可能不存在。要输出0。所以我找到后,又遍历一次判断是不是真的大于 n/2 。效率还是O(N)的

  • 看书的解法。快速排序。是时候去复习一下基本的排序了。撤。


  • 我们有成熟的O(N)算法得到数组中任意第k大的数字--》partition()

  • 刚刚用Partion解法做了一遍。

    感觉穿参数的时候有点绕啊,比如找第k大的,坐标是k-1。

    然后如果一趟快拍之后的坐标 i<k,说明第k大在i后面,

    要传的参数就是 k-i-1;

    综上,我感觉不如在数组前加一个数,放到0位置。这样第k大的数坐标就是k。其他的逻辑也清晰很多。具体是否能行我们在下一题里用一下试试

30 最小的前k个数

  • 先用最low的冒泡AC过了。现在开始去查资料看高端解法~

    • 我错了。我用的方法是比冒泡还low的,纯一个一个比较。
  • vector初始化要声明空间!


  • 用partition的写法试试~

  • 事实证明,在vector的0位置加一个垃圾数。然后整个代码写起来就特别清晰了,可以完全按照思路写出:

    if(i==k)
        return;
    if(i<k){
        partition(vt,i+1,jj,k-i);
    }else
        partition(vt,ii,i-1,k);
    

    如果不在0位置加垃圾数。i就要和k-1做比较,而且k-i那里要写k-i-1


相关文章

  • LeetCode 剑指 Offer 11. 旋转数组的最小数字
    题目链接:LeetCode剑指Offer11.旋转数组的最小数字题意:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [......
  • LeetCode 剑指 Offer 12. 矩阵中的路径
    题目链接:LeetCode剑指Offer12.矩阵中的路径题意:给定一个 mxn二维字符网格 board和一个字符串单词 word。如果 word存在于网格中,返回true;否则,返回false。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元......
  • 【剑指Offer】54、字符流中第一个不重复的字符
    【剑指Offer】54、字符流中第一个不重复的字符题目描述:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。输出描述:如果当......
  • LeetCode 剑指 Offer 08. 二叉树的下一个节点
    题目:二叉树的下一个节点给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。(树的后继)注意:如果给定的节点是中序遍历序列的最后一个,则返回空节点;二叉树一定不为空,且给定的节点一定不是空节点;解题思路二叉树的中序遍历:{[左子树],根节点,[右子树]}如图所示......
  • 金三银四喜提offer!秋招蚂蚁金服Java研发岗四面
     面试流程  先说下面试流程,一般大公司都有3-4轮技术面,1轮的HR面。就蚂蚁金服而言,我共经历了4轮技术面,前两轮主要是问基础和项目实现,第3轮是交叉面,两个面试官,主要是问项目实现和拓展。第4轮是部门老大面,主要就问一些架构、技术和业务的理解、个人发展比较抽象的东西了,现在基......
  • 上月成功拿到字节跳动offer,全靠我啃烂了这份最新面试题
    前言不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的,我这个“有章可循”说的意思只是说应对技术面试是可以提前准备,所谓不打无准备的仗就是这个道理,以下为大家,描述了从面试准备到最后的拿到offer提供了非常详细的......
  • 上月成功拿到字节跳动offer,全靠我啃烂了这份最新面试题
    前言不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的,我这个“有章可循”说的意思只是说应对技术面试是可以提前准备,所谓不打无准备的仗就是这个道理,以下为大家,描述了从面试准备到最后的拿到offer提供了非常......
  • 成功拿下Offer!Salesforce顾问岗位高频面试问题(含答案)
    前不久自由侠部落为某顶级高科技公司成功招聘了一名资深SalesforceBA,年薪颇丰。企业获得了合适的人才,候选人也拿到了满意的薪资,以及更优质的发展平台。此次招聘,印证了市场对资深业务分析师的需求。从收集需求和流程图,到确保项目交付,完成足够的测试,并对用户进行培训,业务分析师......
  • 【LeetCode剑指offer#05】回文链表的两种解法+删除链表中间节点(链表的基本操作)
    回文链表给你一个单链表的头节点head,请你判断该链表是否为回文链表。如果是,返回true;否则,返回false。示例1:输入:head=[1,2,2,1]输出:true示例2:输入:head=[1,2]输出:false提示:链表中节点数目在范围[1,105]内0<=Node.val<=9思路将值复制到数组中后用双指针......
  • 【剑指Offer】44、反转单词序列
    【剑指Offer】44、反转单词序列题目描述:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student.aamI”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的......