面试题打卡——C++版

旋转链表

题解:

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

image-20210531181408684

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head==nullptr||head->next==nullptr)//没有或者只有一个节点
            return head;
        
        int len=0;
        ListNode *cur=head;
        while(cur)//求出链表长度
        {
            len++;
            cur=cur->next;
        }

        k%=len;
        k=len-k;

        cur=head;
        ListNode* prev=nullptr;
        while(k--)
        {
            prev=cur;
            cur=cur->next;
        }
        prev->next=nullptr;
        ListNode* newhead=cur;
        if(cur==nullptr)//此时k==0
            return head;

        while(cur->next)//将旧的头链接在新的头后面
        {
            cur=cur->next;
        }
        cur->next=head;

        return newhead;
    }
};

二叉搜索树中第K小的元素

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

题解:

1.二叉搜索树的中序遍历得到的结果之中,是升序的,求第k个最小的元素,则需输出第k个数即可

2.将K值传引用进入递归函数,中序遍历二叉树

3.每访问一个节点 k–,当k==0时说明,此时访问的节点,即所求节点,用过引用返回值拿出来即可

class Solution {
public:

    void _kthSmallest(TreeNode* root,int &k,int &val)
    {
        if(root==nullptr||val!=-1)
            return ;
        
        _kthSmallest(root->left,k,val);
        k--;
        if(k==0)
        {
            val=root->val;
            return ;
        }
        _kthSmallest(root->right,k,val);
    }

    int kthSmallest(TreeNode* root, int k) {
        int val=-1;
        _kthSmallest(root,k,val);
        return val;
    }
};

Nim游戏

你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头。你们轮流进行自己的回合,你作为先手。每一回合,轮到的人拿掉 1 - 3 块石头。拿掉最后一块石头的人就是获胜者。假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false 。

题解:

1.当n<=3时,直接全部拿走,即可以获得胜利

2.当 n>3时,此时我们需要保证倒数第二轮的时候,剩下的石块的个数正好是4块,并且是对方拿.
这是因为如果倒数第二轮的时候剩下的是4块石头,那么对方一次是拿不完的,并且自己在下一次就可以将全部石块拿完,取得胜利

3.由第2点知晓,我们要保证倒数第二轮是对方拿,并且石块数量是4块,那么这一条件如何实现呢?

只要第一次拿完之后,剩下的石块是4的倍数既可以实现了。 这是因为,第一次拿完,剩下的是4的倍数,不管对方拿多少块,下一次自己拿的时候,只需要将剩余的石块的数量保持为4的倍数即可

class Solution {
public:
    bool canWinNim(int n) {
        //如果想要赢,需要保证倒数第二次的石块数量为4块,并且是对方拿  
        //->  因为不论对方拿几块,自己都可以取得最后的石块

        //第一次自己拿,拿完之后,如果能够保证剩下的石块为4的倍数,即可以获得胜利

        if(n<=3)
            return true;
        
            for(int i=1;i<=3;i++)
            {
                if((n-i)%4==0)//为4的倍数
                    return true;
            }
        return false;
    }
};

链表中的节点每k个一组翻转

将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。
要求空间复杂度 \ O(1) O(1)

image-20210603085522272

题解:

image-20210603094540892

    ListNode *reverse(ListNode *head)//链表逆转
    {
      if(head==nullptr||head->next==nullptr)
        return head;
      
      ListNode *newhead=reverse(head->next);
      head->next->next=head;
      head->next=nullptr;
      return newhead;
    }
  
    ListNode* reverseKGroup(ListNode* head, int k) {
        if(head==nullptr||k==0||head->next==nullptr)
            return head;
      
      vector<ListNode*>arr;//保存每个反转后的头结点
      ListNode *prev=head;
      ListNode *cur=head;
      
      while(cur)
      {
        int count=1;
        while(cur&&count!=k)
        {
          cur=cur->next;
          count++;//来到翻转点
        }
        ListNode *next=nullptr;//保存下一个头结点
        if(cur!=nullptr)//进行翻转
        {
          next=cur->next;//保存下一个节点
          cur->next=nullptr;
          arr.push_back(reverse(prev));//将翻转后的头结点保存起来
          prev=cur=next;//进行更新
        }
        else//剩余节点不够了,不进行反转
        {
          arr.push_back(prev);
          break;
        }
      }
      
      //进行链表的链接
      ListNode* rethead=arr[0];//返回的链表的头
      cur = rethead;
      for(int i=1;i<arr.size();i++)
      {
        ListNode *temp=arr[i];
        while(cur->next)//走到当前链表的末尾
        {
          cur=cur->next;
        }
        cur->next=temp;//将链表链接起来
        cur=temp;//更新链表的头
      }
      
      return rethead;
    }
};

数组中相加和为0的三元组

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

注意:

  1. 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
  2. 解集中不能包含重复的三元组。

题解:

1.对数组排升序

2.构建for循环,从数组中,一次选取值作为 “起始值”

3.由与数组是升序的,因此当num[i] > 0时,直接退出循环 -> 最小的值都大于0了

4.给定两个指针left、right left的位置位于 i+1 right的位于 num.size()-1

5.sum=num[i]+num[left]+num[right]
sum==0时,说明以num[i]为最小值,找到了一个组合 ,此时更新left+1,如果num[left]==num[left-1] ,则继续更新(去重)
sum>0时,总体的值太大了right–
sum<0时,总体的值太小了 left++

6.第5点的循环结束后,说明,以num[i]为最小值的所有组合已经找出来了,继续更新最小值,遇到相同的则直接跳过

class Solution {
public:
    vector<vector<int> > threeSum(vector<int> &num) {
        //先排序,然后选取中心点,再用双指针进行获取内容
      vector<vector<int>>ret;
      
      sort(num.begin(),num.end());
      
      for(int i=0;i<num.size();i++)
      {
        if(i>0&&num[i-1]==num[i])//重复的中心点
           continue;

        if(num[i]>0)
          break;//最小值都大于0
        
         //给定中心点的两个指针
        int left=i+1;
        int right=num.size()-1;
        while(left<right)
        {
          int sum=num[left]+num[i]+num[right];
          if(sum==0)
          {
            vector<int>temp;
            temp.push_back(num[i]);
            temp.push_back(num[left]);
            temp.push_back(num[right]);
            ret.push_back(temp);
           
            //换到新的位置
            left++;
            while(left<right&&num[left]==num[left-1])//同样的值
              left++;
          }
          else if(sum>0)
            right--;
          else
              left++;
        }
      }
      return ret;
    }
};
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值