移动应用开发实验室三面题分析

力扣15三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

3 <= nums.length <= 3000
-105 <= nums[i] <= 105

题目分析

找出相加为0的三元组,每个三元组不能重复

解题思路

直接暴力枚举三层循环会超出时间限制

首先定义一个新的二维数组用于输出,并从小到大排列数组

然后第一层for循环先找出一个值,则能确定另外两个值的和,注意枚举时的去重,去掉nums[i]==nums[i+1]时的值,而不是nums[i]==nums[j]时的值

最后进行剪枝操作,因为已经将数组重排序,所以当值大于目标值时,对于第三层指针,只需将其左移,就可以快速定位

代码实现

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
       vector<vector<int>>ans;//定义一个新的二维数组用于输出
       sort(nums.begin(),nums.end());//从小到大排列
       for(int i=0;i<nums.size();i++)
       {
        if(i>0&&nums[i]==nums[i-1])//必须有i>0的条件,是为了判断与上一个枚举的值不同
        {
            continue;//因为重新排序了 所以这一步可以排除重复的nums[i]值的问题
        }
         int t=-nums[i];
         int k=nums.size()-1;
        for(int j=i+1;j<nums.size();j++)
        {
            if(j>i+1&&nums[j]==nums[j-1])//必须有j+1的条件,道理同上,当nums[i]==nums[j]时,不用跳过此次循环
            {
                continue;
            }
            while(j<k&&nums[j]+nums[k]>t)//当值大于目标值时,对于k指针,只需将其左移,快速定位
            {
                --k;
            }
            if(j==k)break;//j,k指针相遇就跳出
            if(nums[j]+nums[k]==t)
            {
                ans.push_back({nums[i],nums[j],nums[k]});//要用{}
            }
        }
      }
       return ans;
    }
};

力扣2810故障键盘

你的笔记本键盘存在故障,每当你在上面输入字符 ‘i’ 时,它会反转你所写的字符串。而输入其他字符则可以正常工作。

给你一个下标从 0 开始的字符串 s ,请你用故障键盘依次输入每个字符。

返回最终笔记本屏幕上输出的字符串。

示例 1:

输入:s = “string”
输出:“rtsng”
解释:
输入第 1 个字符后,屏幕上的文本是:“s” 。
输入第 2 个字符后,屏幕上的文本是:“st” 。
输入第 3 个字符后,屏幕上的文本是:“str” 。
因为第 4 个字符是 ‘i’ ,屏幕上的文本被反转,变成 “rts” 。
输入第 5 个字符后,屏幕上的文本是:“rtsn” 。
输入第 6 个字符后,屏幕上的文本是: “rtsng” 。
因此,返回 “rtsng” 。
示例 2:

输入:s = “poiinter”
输出:“ponter”
解释:
输入第 1 个字符后,屏幕上的文本是:“p” 。
输入第 2 个字符后,屏幕上的文本是:“po” 。
因为第 3 个字符是 ‘i’ ,屏幕上的文本被反转,变成 “op” 。
因为第 4 个字符是 ‘i’ ,屏幕上的文本被反转,变成 “po” 。
输入第 5 个字符后,屏幕上的文本是:“pon” 。
输入第 6 个字符后,屏幕上的文本是:“pont” 。
输入第 7 个字符后,屏幕上的文本是:“ponte” 。
输入第 8 个字符后,屏幕上的文本是:“ponter” 。
因此,返回 “ponter” 。

提示:

1 <= s.length <= 100
s 由小写英文字母组成
s[0] != ‘i’

题目分析

逐个输入字符串,当字符为i时反转前面的字符串,注意不输入i

解题思路

如果字符为i,利用for循环覆盖i,覆盖后字符串长度-1,并在最后截取字符串加’\0’,否则会多次出现最后一个元素,然后交换’i’前字符串
如果字符不是’i’,记录字符个数用于交换,再进行输入

代码实现

char* finalString(char* s) {
        int j=0;
        int y=strlen(s);
        for(int i=0;i<y;i++)
        {
            if(s[i]=='i')
            {
                int o=i;
                for(o=i;o<y-1;o++)
                {
                    s[o]=s[o+1];
                }
                s[o]='\0';//覆盖后要加'\0'
                i--;//因为覆盖了一个字母 所以要将遍历数字减一
                for(int k=0,p=j-1;k<p;k++,p--)
                {
                    
                        int q;
                        q=s[k];
                        s[k]=s[p];
                        s[p]=q;
                }
            }else{
                j++;
            }
        }
        return s;
}

力扣21合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:

输入:l1 = [], l2 = []
输出:[]
示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

题目分析

将两个有序链表合并为一个有序链表

解题思路

另外定义新链表,依次比较两个链表的值再存入
或直接使用递归将其拼接
问题:使用递归将返回l1还是l2呢?
随着递归使用,当有一个链表为空时,返回另外一个
注意:最后的判断条件不可为l1->val>=l2->next,因为必须要进入if else 语句,否则没有返回值,编译报错
如果新建链表则没有此问题

代码实现

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1==NULL)
        {
            return l2;
        }else if(l2==NULL)
        {
            return l1;
        }else if(l1->val<l2->val)
        {
            l1->next=mergeTwoLists(l1->next,l2);
            return l1;
        }else //不能写l1->next>=l2->next
        {
            l2->next=mergeTwoLists(l1,l2->next);
            return l2;
        }
    }
};

力扣LCR086分割回文串

给定一个字符串 s ,请将 s 分割成一些子串,使每个子串都是 回文串 ,返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

示例 1:

输入:s = “google”
输出:[[“g”,“o”,“o”,“g”,“l”,“e”],[“g”,“oo”,“g”,“l”,“e”],[“goog”,“l”,“e”]]
示例 2:

输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]
示例 3:

输入:s = “a”
输出:[[“a”]]

提示:

1 <= s.length <= 16
s 仅由小写英文字母组成

题目分析

将一个大字符串分割成n个部分,输出所有子串都是回文串的部分,回文串就是左右对称的字符串

解题思路

问题类似于回溯的思想,将一个大问题分割成n个小问题,分而治之
首先设置两个函数,一个利用递归来输出分割后的回文串另一个用于判断是否为回文串,然后主体代码设置两个字符串cur,ret,ret用来存放分割好的字符串cur用来存放不断分割好的字符串
递归的实现:以google为例
先进入第一次for循环,g在pdhw函数中为真,进入if语句,另外定义一个字符串str临时存放回文串,再将str放到cur中
注意此时再次进入helper函数,此时改变起始位置为i+1,从o开始,执行过程与上述一致,i继续加1直到i==s的长度,将cur放到ret里,跳出递归,执行cur.popback,删去分割好的字符串,回溯到初始状态index=0,cur为空

然后再次进入第二次for循环,i为1,go不符合条件,直到goog的pdhw为真再次进入,与上述过程相同

最后返回ret即可

代码实现

class Solution {
private:
    void helper(string&s,int index,vector<vector<string>>&ret,vector<string>&cur){
        if(index==s.size())//跳出条件
        {
            ret.push_back(cur);
            return;
        }
        for(int i=index;i<s.size();i++)
        {
            if(pdhw(s,index,i))
            {
                string str=s.substr(index,i-index+1);//改变内存空间
                cur.push_back(str);
                helper(s,i+1,ret,cur);//后半段
                cur.pop_back();//删去
            }
        }
    }
        bool pdhw(string& s,int left,int right){//判断回文
            while(left<right)
            {
                if(s[left++]!=s[right--])
                {
                    return false;
                }
            }
            return true;
        }
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>>ret;
        vector<string>cur;
        helper(s,0,ret,cur);
        return ret;
    }
};

力扣20有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = “()”
输出:true
示例 2:

输入:s = “()[]{}”
输出:true
示例 3:

输入:s = “(]”
输出:false

提示:

1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成

题目分析

括号的匹配很好理解,左右对应即可,但有效的情况除了示例还可以类似{()}

解题思路

使用数组来模拟栈,定义一个数组模拟栈,当有左侧括号时,将其存放到数组中,即入栈,当有右侧括号与之对应则数组下标左移,即出栈
无效的情况分为两种:1括号位置不匹配,2没有入栈的左侧括号就存在右侧括号

代码实现

bool isValid(char* s) {
   char stk[10010];
    int t = -1;
    for(int i = 0;i < strlen(s);i++){
        if(s[i] == '(' || s[i] == '[' || s[i] == '{') stk[++t] = s[i];
        else{
            if(s[i] == ')'){
                if(t == -1 || stk[t] != '(') return false;
                else if(stk[t] == '(') t--;
            }else if(s[i] == ']'){
                if(t == -1 || stk[t] != '[') return false;
                else if(stk[t] == '[') t--;
            }else if(s[i] == '}'){
                if(t == -1 || stk[t] != '{') return false;
                else if(stk[t] == '{') t--;
            }
        }
    }
    return t == -1;
}

力扣14最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

示例 1:

输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”
示例 2:

输入:strs = [“dog”,“racecar”,“car”]
输出:“”
解释:输入不存在公共前缀。

提示:

1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i] 仅由小写英文字母组成

题目分析

找出字符串最长的公共的前缀,没有则返回空

解题思路

先依次比较各个字符串的第一位,然后第二位依此类推,所以要设置两层for循环,第一层控制字符串的第一位字符,第二层控制各个字符串,当前缀不为公共时,给字符串加上结尾\0,并返回

代码实现

char* longestCommonPrefix(char** strs, int strsSize) {
    //**strs为二维数组,strSize为单词个数
    if (strsSize == 0) {
	return "";
    }
//依次比较每个单词的字母
for (int i = 0; i < strlen(strs[0]); i++) {
	for (int j = 1; j < strsSize; j++) {
		if (strs[0][i] != strs[j][i])
		{
			strs[0][i] = '\0';
			return strs[0];
		}
	}
}
return strs[0];
}
  • 39
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值