【Leetcode】情感丰富的文字、统计有序数组中的负数

简介: 【Leetcode】情感丰富的文字、统计有序数组中的负数

作者:一个喜欢猫咪的的程序员

专栏:《Leetcode》

喜欢的话:世间因为少年的挺身而出,而更加瑰丽。                                  ——《人民日报》


809.情感丰富的文字


题目:

情感丰富的文字

https://leetcode.cn/problems/expressive-words/


题目描述:


有时候人们会用重复写一些字母来表示额外的感受,比如 "hello" -> "heeellooo", "hi" -> "hiii"。我们将相邻字母都相同的一串字符定义为相同字母组,例如:"h", "eee", "ll", "ooo"。


对于一个给定的字符串 S ,如果另一个单词能够通过将一些字母组扩张从而使其和 S 相同,我们将这个单词定义为可扩张的(stretchy)。扩张操作定义如下:选择一个字母组(包含字母 c ),然后往其中添加相同的字母 c 使其长度达到 3 或以上。


例如,以 "hello" 为例,我们可以对字母组 "o" 扩张得到 "hellooo",但是无法以同样的方法得到 "helloo" 因为字母组 "oo" 长度小于 3。此外,我们可以进行另一种扩张 "ll" -> "lllll" 以获得 "helllllooo"。如果 S = "helllllooo",那么查询词 "hello" 是可扩张的,因为可以对它执行这两种扩张操作使得 query = "hello" -> "hellooo" -> "helllllooo" = S。


输入一组查询单词,输出其中可扩张的单词数量。


示例:


输入:

S = "heeellooo"

words = ["hello", "hi", "helo"]

输出:1

解释:

我们能通过扩张 "hello" 的 "e" 和 "o" 来得到 "heeellooo"。

我们不能通过扩张 "helo" 来得到 "heeellooo" 因为 "ll" 的长度小于 3


思路:双指针


经典双指针题型,这里给出C语言解法。


1.在比较每对字符时,分别设置一个起始指针。


2.分别求出每个字符的连续相同个数。


3.基于个数进行判断。


本题我们首先确定当WordSize为0时,我们就不需要比较了,直接返回0就好了。


当wordSize不为0的情况下:


我们以heeellooo(str)和hello(word)为例:


我们要什么时候判断是否是扩张呢?-------------------当我们两个字符串的对应字符相等时!


当对应字符不相等时:


那就是不能扩张,返回0就是了

当对应字符相等时:


我们要将s中sid的位置与sid+1作比较,如果相等,继续比较直到不相等为止。在这个过程中一个变量num1尽量相等的次数。因为我们本题还设立一个变量将便于循环,所以num1要再加一次,num1>=3就是可以扩容的。


我们思考一个情况:当两个字符串的指针来到了llooo(s)和llo(word)时,


num1=2这个时候是不可以扩容的,但两个字符串中的ll都相等。所以是没有问题。


如何解决呢?


我们可以将did的位置和did的下一个位置做比较,跟num1的那个循环一样,利用一个变量num2。当num1==num2时字符串是可以扩容的。


我们这样遍历了两个字符串后,最后当sid和did的位置来到了各自字符串的最后就是可以扩容的,如果没有来到最后就是不能扩容。


时间复杂度:O(N^2)                             空间复杂度:O(1)

代码实现:

int dilate(char* str, char* word)
{
    int sid = 0;
    int did = 0;
    while (did < strlen(word) && sid <strlen(str))
    {
        if (word[did]!= str[sid])
            return 0;
        else
        {
            int num1 = 0;
            for (int i = sid; i < strlen(str); i++)
            {
                 if (str[i] == str[sid])
                    num1++;
                else
                    break;
            }
            int num2 = 0;
            for (int i = did; i < strlen(word); i++)
            {
                if (word[i] == word[did])
                    num2++;
                else
                    break;
            }
            if (num1 == num2 || (num1 > num2 && num1 >= 3))
            {
                sid += num1;
                did += num2;
            }
            else
                return 0;
        }
    }
        if (did < strlen(word) || sid < strlen(str))
            {return 0;}
        else
            {return 1;}
    }
    int expressiveWords(char* s, char** words, int wordsSize)
    {
        if (wordsSize == 0)
            return 0;
        int num = 0;
        for(int i=0;i<wordsSize;i++)
        {
        if(dilate(s, words[i]))
            num++;
        }
        return num;
    }


1351.统计有序数组中的负数


1351. 统计有序矩阵中的负数

https://leetcode.cn/problems/count-negative-numbers-in-a-sorted-matrix/

题目:


给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 请你统计并返回 grid 中 负数 的数目。


示例:


示例 1:


输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]

输出:8

解释:矩阵中共有 8 个负数。

示例 2:


输入:grid = [[3,2],[1,0]]

输出:0


思路:


思路一:暴力解法(就不解释了哈哈哈哈哈哈哈哈哈大家都懂)


时间复杂度:O(N^2)                            空间复杂度:O(1)


思路二:二分查找法


注意到题目中给了一个性质,即矩阵中的元素无论是按行还是按列,都以非递增顺序排列,可以考虑把这个性质利用起来优化暴力。已知这个性质告诉了我们每一行的数都是有序的,所以我们通过二分查找可以找到每一行中从前往后的第一个负数,那么这个位置之后到这一行的末尾里所有的数必然是负数了,可以直接统计。


我们利用begin和end两个找到中间位置n,然后看n下标的值大于0小于0,再找出下一个中间位置,直到找到小于0的地方。

总时间复杂度是O(nlogn)     空间复杂度:O(1)

思路三:杨氏矩阵思想

我们发现从某一列j的数小于0的话,它下面的数都小于0.

前提条件:j=*gridcolsize-1  i=0;

循环结束条件:i<最大行数  || j<0

迭代原理:

1.grid[i][j]<0         j--;

2.grid[i][j]>0         i++;




时间复杂度:O(M+N)                            空间复杂度:O(1)

代码实现:

思路一:

int countNegatives(int** grid, int gridSize, int* gridColSize){
    int num=0;
    for(int i=0;i<gridSize;i++)
    {
        for(int j=0;j<gridColSize[0];j++)
        {
            if(grid[i][j]<0)
            num++;
        }
    }
    return num;
}

思路二:

int countNegatives(int** grid, int gridSize, int* gridColSize){
    int num=0;
    for(int i=0;i<gridSize;i++)
    {
        int m=0;
        int begin=0;
        int end=*gridColSize-1;
        while(begin<=end)
        {
            int n=(begin+end)/2;
            if(grid[i][n]<0)
            {
                end=n-1;
                m=*gridColSize-n;
            }
            else
            {
                begin=n+1;
            }
        }
        num+=m;
    }
    return num;
}

思路三:

int countNegatives(int** grid, int gridSize, int* gridColSize){
    int num=0;
    int i=0;
    int j=*gridColSize-1;
    while(i<=(gridSize-1)&&j>=0)
    {
        if(grid[i][j]<0)
        {
            num=num+gridSize-i;
            j--;
        }
        else
        {
            i++;
        } 
    }
    return num;
}


相关文章
|
23天前
|
存储
【合并两个有序数组】LeetCode第88题讲解
【合并两个有序数组】LeetCode第88题讲解
|
9天前
|
存储 搜索推荐
题目----力扣--合并两个有序数组
题目----力扣--合并两个有序数组
15 0
|
15天前
|
存储 搜索推荐 C语言
Leetcode—合并两个有序数组—C语言
Leetcode—合并两个有序数组—C语言
|
23天前
leetcode代码记录(有序数组的平方
leetcode代码记录(有序数组的平方
13 0
|
23天前
leetcode代码记录(有序数组两数之和
leetcode代码记录(有序数组两数之和
18 0
|
23天前
[leetcode~数位动态规划] 2719. 统计整数数目 hard
[leetcode~数位动态规划] 2719. 统计整数数目 hard
|
23天前
【力扣】80.删除有序数组中的重复项Ⅱ
【力扣】80.删除有序数组中的重复项Ⅱ
|
23天前
【力扣】26.删除有序数组中的重复项
【力扣】26.删除有序数组中的重复项
|
23天前
|
存储 算法
【力扣】88. 合并两个有序数组
【力扣】88. 合并两个有序数组
|
23天前
【力扣】26. 删除有序数组中的重复项
【力扣】26. 删除有序数组中的重复项