【剑指offer专项突破版】数组篇——“C“

news2024/11/26 11:52:05

文章目录

  • 前言
  • 一 . 排序数组中两个数字的和
    • 题目分析
    • 思路分析
      • 法①代码——双指针
      • 法②代码——二分查找
  • 二. 数组中和为 0 的三个数
    • 题目分析
    • 问题转换
    • 代码
  • 三. 和大于等于 target 的最短子数组
    • 题目分析
    • 思路分析
    • 代码
  • 四. 乘积小于 K 的子数组
    • 题目分析
    • 思路分析
    • 代码
  • 五. 和为 k 的子数组
    • 题目分析
    • 思路分析
    • 代码
  • 六. 0 和 1 个数相同的子数组
    • 题目分析
    • 思路分析
    • 代码
  • 七. 左右两边子数组的和相等
    • 题目分析
    • 思路分析
    • 代码
  • 八. 二维子矩阵的和
    • 题目分析
    • 思路分析
    • 代码
  • 总结

前言

剑指offer专项突破版(力扣官网)——> 点击进入
本文所属专栏——>点击进入

一 . 排序数组中两个数字的和

题目分析

在这里插入图片描述

思路分析

关键:利用好升序数组的特性
思路1:可以利用双指针,一个左下边标,一个右下标,这样比目标数大,就让右下标右移,调小。比目标数小,就让左下标左移,调大。
思路2:固定一个值(可以从左边也可以从右边),那么要找的数就是目标值-这个固定的值,这个固定的值就可以利用二分法进行查找。

法①代码——双指针

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{
    //开辟空间并初始化数组
    int *arr = (int*)malloc(sizeof(int)*2);
    *returnSize = 2;
    memset(arr,0,sizeof(int)*2);
    //双指针查找思路
    int left = 0;
    int right = numbersSize - 1;
    while(left < right)
    {
        int sum = numbers[left]+numbers[right];
        if(sum > target)
        {
            right--;
        }
        else if(sum < target)
        {
            left++;
        }
        else
        {
            arr[0] = left;
            arr[1] = right;
            break;
        }
    }
    
    return arr;
}

法②代码——二分查找

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{
    //开辟空间并初始化数组
    int *arr = (int*)malloc(sizeof(int)*2);
    *returnSize = 2;
    memset(arr,0,sizeof(int)*2);
	//二分查找思路
    for(int i = 0; i < numbersSize; i++)
    {
        //从左边开始
        int left = i+1;
        int right = numbersSize - 1;
        int mid = (left+right)/2;
        int Target = target - numbers[i];
        int flag = 0;
        while(left<=right)//这里是可以相等的,因为我要找的是一个数
        {
            if(numbers[mid]>Target)
            {
                right = mid - 1;
            }
            else if(numbers[mid]<Target)
            {
                left = mid + 1;
            }
            else
            {
                flag = 1;
                break;
            }
            //更新mid
            mid = (left+right)/2;
        }
        if(flag)
        {
            arr[0] = i;
            arr[1] = mid;
            break;
        }
    }
    
    return arr;
}

二. 数组中和为 0 的三个数

题目分析

在这里插入图片描述

  • 总结

1.返回值——二维数组——元素为三个元素的数组
2.要求——找到三个不一样(下标)的数,使之相加等于0
3.关键——返回的二维数组中的元素不能重复。

问题转换

 要求是nums[i] + nums[j] + nums[k] == 0,那我们转换一下求满足 nums[j] + nums[k] == -nums[i] ,这样眼熟吗?不就是升序数组中两个数字和等于target吗?但是这个target也在数组中,于是我们要固定taget,然后再求这两个数,如何求呢?因为是升序数组,所以我们要先对数组进行排序。然后遍历数组依次取target,target固定一个边界,那么剩余的另一边的元素,就是我们用双指针的进行找两个元素的范围了。
 剩下有两个细节,第一个——开空间直接开够,这里的的空间开够指的就是所有的可能性之和——从一个数组中选3个元素,不按顺序,有多少种排法?设数组的元素是size,利用高中知识,(size)*(size-1)/(3*2)就为所有可能性,因此我们至少要开这么大的空间;第二个——如何避免重复的三元组,那我们就要想到,为啥会产生重复的三元组?因为有重复的元素,那答案就是跳过重复的元素即可。

  • 总结

第一步:对数组进行排序——qsort的使用
第二步: 开辟一个二维数组——空间足够
第三步:进行遍历取target并确定边界
第四步:找值,找到存储——在一个三个元素的一维数组中。
第五步:调整值。
第六步:返回的一维数组初始化。

代码

int my_cmp(int* e1,int* e2)
{
    return *e1 - *e2;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
{
	//首先说明的是:returnColumnSizes是指向一维数组的指针的指针,
	//因为要修改指针的指向,所以要传进去二级指针!
	
    //第一步——将数组进行排序——升序
    qsort(nums,numsSize,sizeof(int),my_cmp);
    //第二步——将开辟一个二维数组

    //分析:
    //一次一次开的效耗比较大——realloc
    //因此可以一下子把空间开够——那么数组中三个成组的所有可能性就为
    //——从numsSize中选3个不排序
    //因此为——numsSize*(numsSize-1)/(3*2*1)
    int size = numsSize*(numsSize-1)/6;
    int **arr =(int **)malloc(sizeof(int*)*size);
    *returnSize = 0;//*returnSize表示有多少行
    int cur_size = 0;
    //第三步——查找指定的数字
    
    //分析:
    //根据nums[i]+nums[j]+nums[k]==0——>-nums[i] = nums[j]+nums[k]
    //-nums[i]为固定的值,那么我们找的就是 nums[j]+nums[k] = -nums[i]
    //说明:这里的numsize-2说的是最后剩下两个元素就不用进去了,没必要。
    for(int i = 0; i<numsSize-2;)
    {
        //这是要找的条件
        int  target = -nums[i];

        //双指针进行查找
        int left = i+1;
        int right = numsSize-1;
        //printf("hehe");
        while(left<right)
        {
            int sum = nums[left]+nums[right];
            if(sum>target)
            {
                right--;//调小
            }
            else if(sum<target)
            {
                left++;//调大
            }
            else
            {
                //找到了
                int va_l = nums[left];
                int va_r = nums[right];
                //开辟一个一维数组进行存储
                int * tmp = (int*)malloc(sizeof(int)*3);
                tmp[0] = nums[i];
                tmp[1] = nums[left];
                tmp[2] = nums[right];
                //printf("%d",tmp[0]);
                arr[cur_size++] = tmp;
                *returnSize = cur_size;
                //调整部分
                //因为可能有重复多个,原因是存在相等的值,所以如果有要跳过
                while(left<right&&nums[right]==va_r)
                {
                    right--;
                }
                //这里的left可以不用动,因为只要一个动了,就会导致最后的sum
                //也会变,之后的循环就会导致left也跟着变。
            }
        }
        int va_i = nums[i];
        //跳过target的相等的元素。
        while((i<numsSize-2)&&(nums[i]==va_i))
        {
            i++;//至少进一次循环。
        }
    }
    (*returnColumnSizes) = (int*)malloc(sizeof(int)*(*returnSize));
    for(int i = 0; i<(*returnSize);i++)
    {
        (*returnColumnSizes)[i] = 3;
    }
    return arr;
}

三. 和大于等于 target 的最短子数组

在这里插入图片描述

题目分析

1.数据格式——正整数,累加必定递增
2.要求——找到最小长度的连续子数组
3.返回——如果最小长度不存在,返回0,存在,则将最小长度返回。

思路分析

 既然是累加递增,那就先累加,让其保持增长的趋势,如果大于target,那么就要判断这时的长度是否为当前最小的长度,如果是更新最小长度,然后继续找,怎么继续?那就让数组的左边元素不断的减,直到小于target即可。然后再进行上面的这一个动作,加直到大于target,然后再判断,再减。这样直到遍历完即可。

  • 总结

第一步:确定两个边界,左边界和右边界。
第二步:让右边界一直增,直到大于判断,再更新左边界。
第三步:返回最小的长度即可。

代码

int minSubArrayLen(int target, int* nums, int numsSize)
{
    int min_len = 0;
    int left = 0;
    int sum = 0;
    for(int right = 0; right < numsSize; right++)
    {
        sum+=nums[right];
        //这里的left==right时,是当right与left之间只有一个数字时的情况判断。
        while(sum>=target&&left<=right)
        {
            int len = right - left + 1;
            //这需要注意的是当min_len == 0时也得进去。
            if(min_len > len || min_len == 0)
            {
                min_len = len; 
            }
            sum-=nums[left++];
        }
    }
    return min_len;
}

四. 乘积小于 K 的子数组

题目分析

在这里插入图片描述

  • 总结:

1.数据格式——正整数数组——累乘的趋势是递增的
2.要求——求出小于k连续子数组的个数。
3.返回值——连续的的子数组的个数

思路分析

 既然是累乘的趋势也是递增的,那我们当小于k时,求出连续的子数组的个数不就行了,当大于k时,就当乘积除以左边的边界,直到小于就跳出循环,但是怎么求连续的子数组的个数呢?我们可以这样想,假如有数组中有前n个数的乘积都小于k,再增加1个数的之后的乘积还小于k,这时新增的连续的子数组的个数怎么求呢,不就是n+1或者说数组的长度吗?怎么算的呢?
举个简单的例子:

当前数组新增数组新增的连续子数组
[1 , 2][1,2,3][3],  [2,3], [1, 2,3]

看懂了吗? 从最后一个数往前数有几个数就新增了几个子数组
于是我们只需求每次新增了几个子数组即可


  • 总结

第一步:求乘积,定义左边界与右边界——都从0下标开始
第二步:当大于k时,就调整到小于k
第三步: 当小于k时,就计算新增的子数组。
第四步:循环结束,返回子数组的个数。

代码

int numSubarrayProductLessThanK(int* nums, int numsSize, int k)
{
    //乘积
    int sum_product = 1;
    //子数组的个数
    int count = 0;
    //左边界
    int left = 0;
    for(int right = 0; right < numsSize; right++)
    {
        sum_product*=nums[right];
        //判断是否大于k,并且需注意前提left<=right
        while(left<=right&&sum_product>=k)
        {
            sum_product/=nums[left++];
        }
        //这里sum_product必定小于target,因此只需计算新增的个数即可
        count+=(right-left+1);
        //注意:当left -1 == right-> right-left +1 ==0 时,
        //——刚好新增的个数为0。

    }
    return count;
}

五. 和为 k 的子数组

题目分析

在这里插入图片描述

  • 总结

1.数据格式——整数——累加的趋势不确定,因此无法用双指针进行解题。
2.要求——找到和为k连续的子数组。
3.返回——符合要求的子数组的个数

思路分析

 既然无法用双指针,就只能暴力求解了吗?很显然暴力求解是行不通的,如果,有这样一种方法,如果直到前n个数字的和——sum,那么如果前n个数中的第1到j个数相加满足sum-k,那么从第j+1个数到第n个数就是我们要求的k了,那么sum-k出现的次数就是我们要求得的子数组的个数。
图解:
在这里插入图片描述
如果我们有这样的一个数组,可以存储sum-k出现的次数,然后通过sun-k找到次数,再加上就可以了,当我们边找边存的时候,就可以忽略一个条件,下标的比较。因此我们需要一个哈希表,键值(下标)是sum-k,找的是sum-k出现的次数。

代码

~这里手搓了一个简单的哈希表,虽然能过,但是效率很低。这里以后会补充其它解法的。

typedef struct HashNode
{
	int count;//次数
	struct HashNode* next;
}HN;
int Hash_Key(int x)
{
    return x+200000;
}
int find_key(HN**arr,int x,int index)
{
    int key = Hash_Key(x);
    HN * judge = arr[key];
    if(judge==NULL)
    {
        return 0;
    }
    return (judge)->count;
}
void PushBack(HN **arr,int key,int index)
{
    HN* NewNode =(HN*)malloc(sizeof(HN));

    NewNode->count = 0;
    NewNode->next = NULL;
    if(arr[key]==NULL)
    {
        NewNode->count = 1;
        arr[key]=NewNode;
        return;
    }
    else
    {
        HN* cur = arr[key];
        (cur->count)++;
    }
    free(NewNode);
}
//最后销毁一下,偷个懒,知道就行
void Destory(HN**arr)
{

}
int subarraySum(int* nums, int numsSize, int k)
{
    HN **arr = (HN**)malloc(sizeof(HN*)*30000001);
    memset(arr,0,sizeof(HN*)*30000001);
    //首先计算和并存入表中
    int sum = 0;
    int target = 0;
    int count = 0;
    for(int i = 0; i < numsSize; i++)
    {
        sum+=nums[i];
        target = sum-k;
        int ret = find_key(arr,target,i);
        if(sum==k)
        {
            count++;
        }
        count+=ret;
        PushBack(arr,Hash_Key(sum),i);//这里要最后再插入,避免影响
    }
    Destory(arr);
    return count;
}

六. 0 和 1 个数相同的子数组

题目分析

在这里插入图片描述

  • 总结

1.数据格式——0 1
2.要求——找到相同数量的0和1的最长连续的子数组
3.返回要求——返回符合要求的子数组的长度。

思路分析

 将题目转换为,数组相加等于0的子数组的最长的长度。也就是将第五题的思路移到下面,不过需要注意的是,键值虽然还是和,但是里面的值可是最小的下标

代码

~这里也是手搓的一个简单的哈希表,不过跟上面不同的是,这里只需有一个下标即可,如果原来的位置有就看是不是最小的,如果不是最小的,那就更新下标值。

typedef struct HashNode
{
	int i;//下标位置
	struct HashNode* next;
}HN;
int Hash_Key(int x)
{
    return x+100000;
}
int find_key(HN**arr,int x,int index)
{
    int key = Hash_Key(x);
    HN * judge = arr[key];
    if(judge==NULL)
    {
        return -1;
    }
    int smaller = -1;
    HN* cur = arr[key];
    int i = cur->i;
    if(i<index)
    {
        smaller = i;
    }
    return smaller;
}
void PushBack(HN **arr,int key,int index)
{
    HN* NewNode =(HN*)malloc(sizeof(HN));
    NewNode->i = index;
    NewNode->next = NULL;
    if(arr[key]==NULL)
    {
        arr[key]=NewNode;
        return;
    }
    //因为是index是递增的,所以不需要再进行判断了,直接free即可
    // else
    // {
    //     HN* cur = arr[key];
    //     if(index<cur->i)
    //     {
    //         cur->i = index;
    //     }
    // }
    free(NewNode);
}
//最后销毁一下
void Destory(HN**arr)
{
}
int findMaxLength(int* nums, int numsSize)
{
    HN **arr = (HN**)malloc(sizeof(HN*)*200001);
    memset(arr,0,sizeof(HN*)*200001);
    
    int sum = 0;
    int target = 0;
    int max_len = 0;
    for(int i = 0; i < numsSize; i++)
    {
        sum += nums[i] == 0 ? -1 : 1;
        target = sum;
        int left = find_key(arr,target,i);
        if(left!=-1)
        {
            int len = i-left;//左开右闭
            if(len>max_len)
            {
                max_len = len;
            }
        }
        if(sum==0)
        {
            max_len = i+1;
        }
        //这里要最后再插入,避免影响
        PushBack(arr,Hash_Key(sum),i);
    }
    Destory(arr);
    return max_len;
}

七. 左右两边子数组的和相等

题目分析

在这里插入图片描述
中心下标示例:
在这里插入图片描述

  • 总结

1.数据格式——整数
2.要求——求最左边的的中心下标
3.返回值——如果不存在返回-1,否则返回符合要求的中心下标
4.特殊情况:如果在最左边,那么其左边元素之和视为0。右边同理。

思路分析

 首先暴力求解不可取,那么如何求解呢?根据中心下标左边之和等于右边之和,很显然右边之和等于 整体之和减去左边之和中心下标元素之和。那么我们只需要遍历一遍数组求出前n个数字的和,再运用前n个数字的和遍历数组利用上面的条件即可求解。

  • 总结

第一步:求出前n个数字的和。
第二步:定义sum(左边之和加上中心下标元素)变量,循环遍历数组。
第三步:利用条件判断是否相等,相等则跳出循环,否则继续遍历。
第四步:返回中心下标。

代码

int pivotIndex(int* nums, int numsSize)
{
    int tar_index = -1;

    //求前n个数字之和
    int sum = 0;
    for(int i = 0; i < numsSize; i++)
    {
        sum += nums[i];
    } 
    
    int cur_sum = 0;//就等于左边的和 + 中心下标
    for(int i = 0; i < numsSize; i++)
    {
        cur_sum += nums[i];
        //左边的和
        int left = cur_sum - nums[i];
        //右边的和
        int right = sum - cur_sum; 
        if(right == left)
        {
             tar_index = i;
             break;
        }
    }
    return tar_index;
}

八. 二维子矩阵的和

题目分析

在这里插入图片描述

  • 总结

要求:
1.完成对二维数组——存放在结构体中的初始化
2.完成图中的求和工作
3.对结构体的空间进行释放

思路分析

 首先开门见山,关键在于求和工作,其它的没那么难,不用想了暴力求解肯定不行,那咋求?
图解:
在这里插入图片描述
补充:如何求(0,0)到(i,j)的长度,比如一个数组是这样的。
在这里插入图片描述

  • 总结:

1.开辟一个求和数组(存放求和结果)——比原来的要求和的数组多上1行1列
2.利用求和公式求解即可。

代码

typedef struct 
{
    int **arr;
    int matrix;
    int *matrixColSize;
    int **sum;

} NumMatrix;


NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) 
{
    //一行含有多少个元素
    int colsize = matrixColSize[0];  
    NumMatrix* tmp = (NumMatrix*)malloc(sizeof(NumMatrix));
    tmp->arr = (int**)malloc(sizeof(int*)*matrixSize);
    tmp->matrix = matrixSize;
    tmp->matrixColSize = (int*)malloc(sizeof(int)*matrixSize);

    tmp->sum = (int**)malloc(sizeof(int*)*(matrixSize+1));
    //首先要开辟一行
    int * col = (int*)malloc(sizeof(int)*(colsize+1));
    memset(col,0,sizeof(int)*(colsize+1));
    (tmp->sum)[0] = col;
    for(int i = 0; i < matrixSize; i++)
    {
        (tmp->matrixColSize)[i] = colsize;
    }
    //进行初始化,并完成求和工作
    for(int i = 0; i < matrixSize; i++)
    {
        int * col_sum = (int*)malloc(sizeof(int)*(colsize+1));
        memset(col_sum,0,sizeof(int)*(colsize+1));
        int * col = (int*)malloc(sizeof(int)*colsize);
        //定义求和变量
        int sum = 0;
        for(int j = 0; j < colsize; j++)
        {
            //完成累加操作
            sum+=matrix[i][j];
            //完成赋值操作
            col[j] = matrix[i][j];
            //完成求和操作
            col_sum[j+1] = sum + (tmp->sum)[i][j+1]; 
        }
        //完成赋值
        (tmp->arr)[i] = col;
        (tmp->sum)[i+1] = col_sum;
    }
    return tmp;
}

int numMatrixSumRegion(NumMatrix* obj, int row1, int col1, int row2, int col2) 
{
    int **arr = obj->sum;
    //arr[row2][col2]-arr[row1-1][col2]-arr[row2][col1-1]+arr[row1-1][col1-1]-在此基础上加一即可
    int sum = arr[row2+1][col2+1]\
    -arr[row1][col2+1]-arr[row2+1][col1] + arr[row1][col1];
    return sum;
}
void numMatrixFree(NumMatrix* obj) 
{
    int **arr = obj->arr;
    int **sum = obj->sum;
    int * col = obj->matrixColSize;
    free(sum);
    free(arr);
    free(col);
}

总结

  • 前四道题,可以说是将双指针的用法展现的淋漓尽致。
  • 第五道和第六道大同小异,不过都是得用哈希表存储,这样的效率会高一些。
  • 第七道和第八道的思路雷同,不过是一维到二维而已。
  • 第五道到第八道的解题思路很相似,可以说都跟求和有关,但是对求和的使用场景却不一样。
  • 有些题看起来不一样,但是可以奇妙的转换成相同的思路,这就是灵活运用!

最后希望这篇文章对您有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/627476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023 年前端 Web 发展趋势

虽然就个人观点&#xff0c;我觉得 Web 开发在最近几年都没什么进展&#xff08;2016 年至 2021 年&#xff09;&#xff0c;但在刚刚过去的 2022 年中确实又出现了一些新的技术。在本文中&#xff0c;我想跟大家聊聊自己看到的最新 Web 开发的发展趋势。相信这波浪潮会继续激发…

PLC采集串口被占用、网口被占用,网络IP地址不能修改、多台设备IP不同网段等问题解决方案

在我们数据采集项目中&#xff0c;经常碰到端口被串口被触摸屏占用&#xff0c;网口被占用&#xff0c;修改IP增加风险&#xff0c;另外增加新的端口需要通过PLC的编程软件组态&#xff0c;涉及到上传下载PLC程序&#xff0c;耗时耗力很不方便。以下是我们总结的项目中解决办法…

JVM-对象布局

JVM中对象布局 通过引入JOL工具&#xff0c;查看对象在JVM中的布局。 <dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.14</version></dependency>对象的在JVM中的基本信息 普通…

iconfont字体的引用

官网&#xff1a;giconfont-阿里巴巴矢量图标库iconfont-国内功能很强大且图标内容很丰富的矢量图标库&#xff0c;提供矢量图标下载、在线存储、格式转换等功能。阿里巴巴体验团队倾力打造&#xff0c;设计和前端开发的便捷工具https://www.iconfont.cn/1. 搜索图标&#xff0…

【正点原子STM32连载】 第三十章 ADC实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第三十…

2023最新项目管理软件排行榜!快来了解各大品牌优缺点

项目管理是一个复杂而又多样化的过程。在这个过程中&#xff0c;管理者需要处理大量的信息&#xff0c;规划资源&#xff0c;分配任务和监督进展。为了更好地管理项目&#xff0c;许多企业和组织开始采用项目管理软件。这些软件不仅可以帮助管理者更好地处理信息&#xff0c;还…

让你不再疑惑怎么转换音频格式

你是否有过这样的经历&#xff1f;听到了一首喜欢的歌曲&#xff0c;但是只能在特定的平台或设备上播放&#xff0c;因为它只存在于视频网站或某个应用程序中。或者你想要将一首歌曲作为铃声或者用于其他用途&#xff0c;但是音频文件的格式却不被平台所支持。这是&#xff0c;…

3D数字孪生技术在水利工程上面的应用价值

"农功今可济,水利更毋隳。”水利作为国民经济稳定和谐的重要部分&#xff0c;运用科技化手段对水利项目进行管理&#xff0c;能完美契合智慧水利灾害管理与防治所需。深圳华锐视点利用数字孪生和三维可视化技术搭建的智慧水利可视化管理平台&#xff0c;通过web3d开发建模…

软考A计划-系统架构师-官方考试指定教程-(10/15)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

传统ERP软件如何SaaS化?

01 ERP和SaaS ERP概念 企业资源计划 (ERP) 系统是许多企业的主干&#xff0c;助力管理整个企业内的会计、采购流程、项目等。对于许多 IT 部门而言&#xff0c;ERP 系统通常意味着大型、昂贵且耗时的部署&#xff0c;并可能需要进行大量硬件或基础设施投资。然而&#xff0c;云…

【算法基础】拓扑排序及实战

一 、概览 这里涉及到图的概念&#xff0c;感兴趣的同学请移驾 –>图<– 下面还有两个相关概念&#xff0c;大概说一下&#xff1a; 1.1 有向无环图 定义&#xff1a;在图论中&#xff0c;如果一个有向图从任意顶点出发无法经过若干条边回到该点&#xff0c;则这个图是…

测试者必知—如何做Web测试?常见测试点总结

目录 前言&#xff1a; 一、Web应用程序 二、功能测试 三、易用性测试&#xff08;界面测试&#xff09; 四、兼容性测试 五、安全性测试 六、性能测试 前言&#xff1a; Web测试是指对基于Web技术的应用程序进行测试&#xff0c;以测试其功能、性能、安全和稳定性等方面的表…

C++使用boost::serialization进行序列化

废话 发现一个比较好玩的东西&#xff0c;boost::serialization序列化操作&#xff0c;简单来说感觉像ofstream和ifstream的升级版&#xff0c;Boost.Serialization 库能够将c项目中的对象转换为一序列的比特&#xff08;bytes&#xff09;&#xff0c;用来保存和加载还原对象…

PPT里的逆天功能之-PPT扣图(可以秒杀PS的扣图功能)

PPT的扣图功能秒杀PS PPT其实非常强大,它里面有数不甚数的功能是我们之前从未使用过的。比如说PPT的扣图功能。比如说我们有一个背景是灰黑的。 而我们网上可以下到的一些logo很多是带有底色的,它会和我们的背景形成很大的反差。此时我们往往就会用PS工具。这就会让大都IT们…

leetcode数据库题第四弹

leetcode数据库题第四弹 619. 只出现一次的最大数字620. 有趣的电影626. 换座位627. 变更性别1045. 买下所有产品的客户1050. 合作过至少三次的演员和导演1068. 产品销售分析 I1070. 产品销售分析 III1075. 项目员工 I1084. 销售分析III小结 619. 只出现一次的最大数字 https:/…

MySQL的JDBC编程详解

1.JDBC编程概念 在实际项目中&#xff0c;我们对于数据库的操作大部分是通过代码来完成的&#xff0c;各种数据库在开发的时候&#xff0c;都会提供一组编程接口API。所以不同公司使用不同的数据库软件&#xff0c;那么程序员学习成本是非常大的&#xff0c;因为要学习不同数据…

超好用的5款软件,每一款都让你爱不释手

分享爱&#xff0c;分享时光&#xff0c;分享精彩瞬间&#xff0c;大家好&#xff0c;我是互联网的搬运工&#xff0c;今天继续给大家带来几款好用的软件。 1.GIF录制——LICEcap ​ LICEcap是一款用于录制屏幕为GIF动画的工具。它可以让你用一个可调整的窗口来捕捉你的屏幕上…

2023年前端面试高频考点HTML5+CSS3

目录 浏览器的渲染过程⭐⭐⭐ CSS 、JS 阻塞 DOM 解析和渲染 回流&#xff08;重排&#xff09;和重绘⭐⭐ 选择器 ID选择器、类选择器、标签选择器&#xff08;按优先级高到低排序&#xff09;⭐⭐ 特殊符号选择器&#xff08;&#xff1e;,,~&#xff0c;空格&#xff0…

【JavaEE】网络编程之TCP套接字

目录 1、TCP套接字 1.1、ServerSocket 常用API 1.2、Socket 常用API 2、基于TCP套接字实现一个TCP回显服务器 2.1、服务器端代码 2.2、客户端代码 2.3、解决服务器不能同时和多个客户端建立链接的问题 3、基于TCP socket 写一个简单的单词翻译服务器 1、TCP套接字 T…

【中文编程】青语言

【引言】 青语言主页&#xff1a;https://qingyuyan.cn 青语言文档&#xff1a;https://doc.qingyuyan.cn 青语言社区&#xff1a;https://forum.qingyuyan.cn 青语言仓库&#xff1a;https://gitee.com/NjinN/Qing 长久以来&#xff0c;中文编程一直是开发者社区中争议不断的…