移动应用开发实验室第一次考核试题分析

目录


第一题:括号的最大嵌套深度

        如果字符串满足以下条件之一,则可以称之为 有效括号字符串(valid parentheses string,可以简写为 VPS):

  • 字符串是一个空字符串 "",或者是一个不为 "(" 或 ")" 的单字符。
  • 字符串可以写为 AB(A 与 B 字符串连接),其中 A 和 B 都是 有效括号字符串 。
  • 字符串可以写为 (A),其中 A 是一个 有效括号字符串 。

类似地,可以定义任何有效括号字符串 S 的 嵌套深度 depth(S):

  • depth("") = 0
  • depth(C) = 0,其中 C 是单个字符的字符串,且该字符不是 "(" 或者 ")"
  • depth(A + B) = max(depth(A), depth(B)),其中 A 和 B 都是 有效括号字符串
  • depth("(" + A + ")") = 1 + depth(A),其中 A 是一个 有效括号字符串

例如:""、"()()"、"()(()())" 都是 有效括号字符串(嵌套深度分别为 0、1、2),而 ")(" 、"(()" 都不是 有效括号字符串 。

给你一个 有效括号字符串 s,返回该字符串的 s 嵌套深度 。

示例 1:

输入:s = "(1+(2*3)+((8)/4))+1"
输出:3
解释:数字 8 在嵌套的 3 层括号中。

示例 2:

输入:s = "(1)+((2))+(((3)))"
输出:3

 

提示:

1 <= s.length <= 100
s 由数字 0-9 和字符 '+'、'-'、'*'、'/'、'('、')' 组成
题目数据保证括号表达式 s 是 有效的括号表达式

【题目分析】

        题目介绍了什么是嵌套深度。读懂概念后,我们知道了此题只用处理括号就可以了。

【解题思路】

        本题可以用栈的思想。首先遍历字符串 s,如果遇到一个左括号,将其入栈,遇到一个右括号,那么弹出栈顶的左括号,与该右括号匹配。这一过程中的栈的大小的最大值,即为 s 的嵌套深度。

【代码部分】

#define Max(a, b) ((a) > (b) ? (a) : (b))

int maxDepth(char *s){
    int ans = 0, size = 0;//size为栈的大小,ans保存遍历过程中size的最大值即嵌套深度。 
    int len = strlen(s);
    for (int i = 0; i < len; i++) {
        if (s[i] == '(') {
            size++;
            ans = Max(ans, size);
        } else if (s[i] == ')') {
            size--;
            ans = Max(ans, size);
        }
    }
    return ans;
}

第二题:删除链表的中间节点

给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。

长度为 n 链表的中间节点是从头数起第 [n / 2]个节点(下标从 0 开始),其中 [x] 表示小于或等于 x 的最大整数。

对于 n = 1、2、3、4 和 5 的情况,中间节点的下标分别是 0、1、1、2 和 2 。
 

示例 1:

 

输入:head = [1,3,4,7,1,2,6]
输出:[1,3,4,1,2,6]
解释:
上图表示给出的链表。节点的下标分别标注在每个节点的下方。
由于 n = 7 ,值为 7 的节点 3 是中间节点,用红色标注。
返回结果为移除节点后的新链表。 

示例 2:

 

输入:head = [1,2,3,4]
输出:[1,2,4]
解释:
上图表示给出的链表。
对于 n = 4 ,值为 3 的节点 2 是中间节点,用红色标注。

示例 3:

输入:head = [2,1]
输出:[2]
解释:
上图表示给出的链表。
对于 n = 2 ,值为 1 的节点 1 是中间节点,用红色标注。
值为 2 的节点 0 是移除节点 1 后剩下的唯一一个节点。

提示:

链表中节点的数目在范围 [1, 105] 内
1 <= Node.val <= 105

【题目分析】

        题目给出一个链表,要求删除链表的中间节点,返回链表。

【解题思路】

        开始没用快慢指针,直接遍历链表得出节点数除以2,然后再次循环在一半处删除节点。之后发现可以用快慢指针,就又写了一遍。

【代码部分】

最初的代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* deleteMiddle(struct ListNode* head){
    int k = 0;
    struct ListNode *p, *s;
    p = head;
    s = head;
    if(head == NULL || head->next == NULL)
        return NULL;
    while(p){
        k++;
        p = p->next;
    }
    k = k / 2;
    for(int i = 1; i < k; i++){
        s = s->next;
    }
    s->next = s->next->next;
    return head;
}

快慢指针版

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* deleteMiddle(struct ListNode* head){
    struct ListNode *l = head, *p = head->next;
    if(p == NULL){//节点数为1,中间节点为本身,删除后返回NULL
        return NULL;
    }
    if(p->next){
        p = p->next;
    }
    else{
        l->next = p->next;
        return l;
    }
    while(p){
        p = p->next;
        if(p){
            p = p->next;
        }
        else{
             l->next = l->next->next;
                return head;
        }
        l = l->next;
    }
    l->next = l->next->next;
    return head;
}

 

第三题:有序数组的平方

        给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

提示:

1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 已按 非递减顺序 排序

进阶:   

  • 请你设计时间复杂度为 O(n) 的算法解决本问题

【题目分析】

        此题给出一个非递减的数组,要求将数组中的每个元素平后再排序输出。

【解题思路】

        首先定义一个原数组大小的新数组进行存储平方后的数字,之后进行排序,返回新数组。

        这样的思路最简单,但是时间复杂的没有达标。

        我们继续分析,原来的思路没有很好的利用题目中信息——给出的数组 nums 是已经排序好的。如果数组 nums 中的所有数都是非负数,那么将每个数平方后,数组仍然保持升序;如果数组 nums 中的所有数都是负数,那么将每个数平方后,数组会保持降序。所以只要找到原数组正负分界就不必进行排序了。找到正负边界线后,平方后,我们就得到了两个已经有序的子数组,之后可以使用归并的方法进行排序。使用两个指针分别指向位置 neg 和  neg+1,每次比较两个指针对应的数,选择较小的那个放入答案并移动指针。当某一指针移至边界时,将另一指针还未遍历到的数依次放入答案。

【代码部分】

开始的代码

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* sortedSquares(int* nums, int numsSize, int* returnSize){
    int *array = (int*)malloc(numsSize*sizeof(int));
    int i, j;
    for(i = 0; i < numsSize; i++){
        array[i] = nums[i] * nums[i];
    }
    for(i = 0; i < numsSize - 1; i++){
        for(j = 0; j < numsSize - i - 1; j++){
            if(array[j] > array[j+1]){
                int temp;
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
    *returnSize = numsSize;
    return array;
}

改进后的代码

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

int* sortedSquares(int* nums, int numsSize, int* returnSize) {
    int *array = (int*)malloc(numsSize*sizeof(int));
    int temp = -1;
    for (int i = 0; i < numsSize; i++) {//找到正负分界线 
        if (nums[i] < 0) {
            temp = i;
        }
		else {
            break;
        }
    }
    *returnSize = 0;
    int i = temp, j = temp + 1;
    while (i >= 0 || j < numsSize){
        if (i < 0) {//全正
            array[(*returnSize)++] = nums[j] * nums[j];
            j++;
        }
		else if (j == numsSize){//全负
            array[(*returnSize)++] = nums[i] * nums[i];
            i--;
        }
		else if (nums[i] * nums[i] < nums[j] * nums[j]){
            array[(*returnSize)++] = nums[i] * nums[i];
            i--;
        }
		else {
            array[(*returnSize)++] = nums[j] * nums[j];
            j++;
        }
    }
    return array;
}

 

第四题:压缩字符串

给你一个字符数组 chars ,请使用下述算法压缩:

从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符

  • 如果这一组长度为 1 ,则将字符追加到 s 中。
  • 否则,需要向 s 追加字符,后跟这一组的长度。

压缩后得到的字符串 s 不应该直接返回 ,需要转储到字符数组 chars 中。需要注意的是,如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。

请在 修改完输入数组后 ,返回该数组的新长度。

你必须设计并实现一个只使用常量额外空间的算法来解决此问题。

示例 1:

输入:chars = ["a","a","b","b","c","c","c"]
输出:返回 6 ,输入数组的前 6 个字符应该是:["a","2","b","2","c","3"]
解释:"aa" 被 "a2" 替代。"bb" 被 "b2" 替代。"ccc" 被 "c3" 替代。

示例 2:

输入:chars = ["a"]
输出:返回 1 ,输入数组的前 1 个字符应该是:["a"]
解释:唯一的组是“a”,它保持未压缩,因为它是一个字符。

示例 3:

输入:chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]
输出:返回 4 ,输入数组的前 4 个字符应该是:["a","b","1","2"]。
解释:由于字符 "a" 不重复,所以不会被压缩。"bbbbbbbbbbbb" 被 “b12” 替代。

提示:

1 <= chars.length <= 2000
chars[i] 可以是小写英文字母、大写英文字母、数字或符号

【题目分析】

        题目给了我们一段字符串,要求原地进行压缩。在完成原地修改输入数组后,返回数组的新长度。

【解题思路】

        将数组原地压缩,我们可以采用双指针的方法。首先这个题需要设置两个指针,一个写数据的 write ,还有一个读取元素的 read 。

        每当读指针 read 移动到某一段连续相同子串的最右侧,我们就在写指针 write 处依次写入该子串对应的字符和子串长度。

        在读指针 read 位于字符串的末尾或此时read指向的字符不同于其下一个字符时,就可以判断 read 位于某一段连续相同字符串的最右侧。我们使用变量 begin 记录该连续相同字符串开始的位置,这样就可以计算出该连续相同字符串长度 num 为 read−begin+1 。

        另外,题目中要求空间复杂度为常量,我们需要将数字转化为字符串写入到原字符串。这里我们可以使用短除法来实现将该连续相同字符串的长度倒序写入原字符串中。

        在这里说一下什么是短除法。以前做求两个数的最大公约数时,我们用的是辗转相除法递归来做的,但在上学时期,我们采用短除法来做。短除法也叫倒除法,下来我们看一个例子。

假设有两个数 a=12,b=18 ,初始化最大公约数 s=1

我们发现 2 是12和18的一个公因子

我们令 a /= 2 ,b /= 2 ,s *= 2

现在 a = 6 ,  b = 9 ,  s = 2

又发现 3 是 6 和 9 的一个公因子

我们令 a /= 3 ,  b /= 3 ,  s *= 3

现在a = 2 ,  b = 3 ,  s = 6

我们找不到除 1 以外的 2 和 3 的公因子了

所以现在的 s == 6 就是我们要找的最大公约数

【代码部分】

void swap(char *a, char *b);//交换 
void reverse(char *a, char *b);//数字反转
int compress(char *chars, int charsSize){
    int write = 0, begin = 0;
    for (int read = 0; read < charsSize; read++){
        if (read == charsSize - 1 || chars[read] != chars[read + 1]){ 
            chars[write++] = chars[read];
            int num = read - begin + 1;//计算该连续相同字符串的长度
            if (num > 1){
                int anchor = write;
                while (num > 0){
                    chars[write++] = num % 10 + '0';
                    num /= 10;
                }
                reverse(&chars[anchor], &chars[write]);
            }
            begin = read + 1;//重新开始新的字串
        }
    }
    return write;
}
void swap(char *a, char *b){
    char t = *a;
    *a = *b, *b = t;
}
void reverse(char *a, char *b){
    while (a < b) {
        swap(a++, --b);
    }
}

第五题:盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例 1:

 

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

提示:

n == height.length
2 <= n <= 105
0 <= height[i] <= 104

【题目分析】

        题目要求找出数组中两条线与 x 轴共同构成的容器的最大面积。返回面积。

【解题思路】

        首先用两个指针分别指向头和尾,然后判断两个指针的值,哪个更小,就移动哪个指针。在遍历过程中用 max 记录面积最大值。

【代码部分】

int maxArea(int* height, int heightSize){
    int left = 0, right = heightSize-1;
    int max, s;
    max = 0;
    while(left != right){
        if(height[left] >= height[right]){
            s = height[right] * (right - left);
            right = right-1;
        }
        else{
            s = height[left] * (right - left);
            left = left + 1;
        }
        if(s > max)
            max = s;
    }
    return max;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值