双指针训练

news2024/12/23 0:40:41

1.原理

双指针是一种解题常用方法,常用于将数组按照某种要求进行分块/划分,这里的指针对于数组来说,可以替换成下标(毕竟使用下标实际上就是用了指针)。

1.1.划分区间

通常将这两个指针命名位dest/cur(或者begin/end),利用这两个指针将区间划分为三个不同性质的区间[0, dest-1][dest, cur-1][cur, n-1],在cur移动的时候,保持三个区间的性质不变。

实际上这也是快速排序中的前后指针、三路划分中使用的原理。仔细回想一下,快速排序的算法逻辑中,实际上也是将下标[left, right]之间的数据划分为[left, key-1][key, key][key+1, right],并且让这三个区间保持某种性质不变(在快排中是第一个区间比key小/大,最后一个区间比key大/小)。

具体可以看一下这一道:[2.1.[283. 移动零]](##2.1.[283. 移动零])。

1.2.覆盖重写

利用双指针可以达到覆盖数组的目的,这里可以看看:[2.2.[1089. 复写零]](##2.2.[1089. 复写零])。

1.3.快慢指针

经典的应用就是判断链表是否带环,可以看看:[2.3.[202. 快乐数]](##2.3.[202. 快乐数])。

1.4.单调性

有些时候将序列排序后使用双指针会有很高效的解法,可以看看:[2.5.[611. 有效三角形的个数]](##2.5.[611. 有效三角形的个数])、[2.6.[LCR 179. 查找总价格为目标值的两个商品]](##2.6.[LCR 179. 查找总价格为目标值的两个商品])

2.题目

2.1.283. 移动零

这道题目的解法有很多,这里我写一个常见的解法:使用cur扫描/遍历数组,使用dest来作为分界线,在划分成的[0,dest-1][dest, cur-1][cur, n-1]中,三个区间的性质是:[0,dest-1]是已经处理过确认非0的区间,[dest, cur-1]是确认为0的区间,[cur, n-1]是待处理的部分,然后接下来一直移动cur直至[cur, n - 1]为空,区间一直保持以上的性质。

class Solution
{
public:
    void moveZeroes(vector<int>& nums)
    {
        size_t dest = 0;   
        size_t cur = 0;     
        while(cur < nums.size())
        {
            if(nums[cur] != 0)
            {
                std::swap(nums[cur], nums[dest]);
                dest++;
            }
            cur++;
        }
    }
};

时间复杂度为 O ( n ) O(n) O(n),因为只需要遍历一次即可解决问题
空间复杂度为 O ( 1 ) O(1) O(1),因为不计输入数据,只用到了两个有限的变量

2.2.1089. 复写零

首先最容易想到的就是使用另外一个vector<int> ret顺序表来存储复写后的数组,并且拷贝回vector<int> arr即可。

class Solution
{
public:
    void duplicateZeros(vector<int>& arr)
    {
        std::vector<int> ret;
        for(auto it : arr)
        {
            ret.push_back(it);
            if(it == 0)
            {
                ret.push_back(0);
            }
        }
        int i = 0;
        for(auto& it : arr)
        {
            it = ret[i]; 
            i++;
        }
    }
};

虽然可以过,但是忽略了“就地修改”这个规则,这又该怎么办呢?

我们可以定义一个size指向“复写操作后数组”的最后一个元素,cur指向“复写操作前数组”的最后一个元素,也就是说:对于arr=[1,0,2,3,0,4,5,0]经过复写操作后为ret=[1,0,0,2,3,0,0,4]。因此cur下标指向arr[5]=4的位置,假设size下标指向arr[7]=0的位置,然后从右往左判断覆盖(非0arr[7]=arr[5]0则复写两个0),重复操作即可。

但是怎么找到“复写操作后数组”的最后一个元素的下标呢?依旧可以使用双指针寻找,你么看错,就是双指针里面套双指针。

  1. 我们假设size=0, cur=0然后让cur遍历整个数组,只要遇到0就让size+=2, cur++,如果是遇到非0就让size++, cur++
  2. 也就是说size实时记录了“复写操作后数组”的大小
  3. 最后遍历完整个数组,此时的cur一定指向复写操作后数组的最后一个元素的后面
  4. 然后执行之前说的“从右向左覆盖”操作即可
class Solution
{
public:
    void duplicateZeros(vector<int>& arr)
    {
        //1.寻找复写操作后,数组的最后一个元素
        int cur = 0;//寻找“复写操作后数组”的最后元素的下标
        int size = 0;//记录“复写操作后数组”的大小

        //[例子1]
        //复写前:[1,5,2,0,6,8,0,6,0]
        //复写后:[1,5,2,0,0,6,8,0,0]
        //[例子2]
        //复写前:[5,2,1,3,0]
        //复写后:[5,2,1,3,0]0 会溢出一个0
        while (size < (int)arr.size())
        {
            if (arr[cur] == 0)
            {
                size += 2;
            }
            else
            {
                size += 1;
            }
            cur++;
        }
        cur--;
        size--;

        //2.从右往左做开始复写
        //[例子1]
        //复写前:[1,5,2,0,6,8,0,6,0],cur->arr[5]=4, size->arr[7]=0
        //复写后:[1,5,2,0,0,6,8,0,0]
        //[例子2]
        //复写前:[5,2,1,3,0],cur->arr[4]=0, size->arr[5] 越界了 
        //复写后:[5,2,1,3,0]0 会溢出一个0

        if (arr[cur] == 0 && size >= arr.size())
        //当出现最后一个元素为0的时候很特殊,有两种可能:
        //1.复写操作后溢出了一个0,这种情况只复写一次即可
        //2.复写操作后刚好最后两个元素为0,这种情况正常复写即可
        {
            size--;
            arr[size] = arr[cur];
            size--;
            cur--;
        }
        while (cur != -1)
        {
            if (arr[cur] != 0)
            {
                arr[size--] = arr[cur--];
            }
            else
            {
                arr[size--] = arr[cur];
                arr[size--] = arr[cur];
                cur--;
            }
        }
    }
};

时间复杂度为 O ( n ) O(n) O(n),两次循环就是 O ( n + n ) = O ( 2 n ) O(n+n)=O(2n) O(n+n)=O(2n),也就是 O ( n ) O(n) O(n)
空间复杂度为 O ( 1 ) O(1) O(1),只用到了常数个有限的变量

2.3.202. 快乐数

实际上这是一道双链表判断是否回环的问题,可以使用快慢指针(双指针的一种使用方法)来判断链表是否存在回环点。本题最麻烦的问题就是如何知道是否会出现无限循环的情况。

image-20230929230111870
using namespace std;
class Solution
{
private:
    int _function(int number)//计算平方值
    {
        int add = 0;
        while (number)
        {
            add += (number % 10) * (number % 10);
            number /= 10;
        }
        return add;
    }
public:
    bool isHappy(int number)
    {
        //循环判断是否happy
        int p = number;//走一步的指针(慢指针)
        int curp = number;//走两步的指针(快指针)
        while (true)
        {
            p = _function(p);//得4,走一步...
            curp = _function(_function(curp));//得16,走两步...
            if (p == curp)//如果找到循环点,也就是快慢指针相遇,就进入if语句
            {
                if (p == 1)//如果相遇点处的值为1就返回true
                {
                    return true;
                }
                return false;//如果不是1就返回false
            }
        }
    }
};

但是这道题目实际上是出简单的了,题目已经提前告诉我们取平方后只有两种情况:

  1. 最后得到1(实际上也是循环)
  2. 最后是无限循环,一直在一个回环里循环

但是实际上,从简单的思考上,是否存在:无限计算下去得不到1,但是不存在环的可能?我们可以使用”鸽笼原理“:在n个鸽笼中放入n+1只鸽子,则至少有一个笼子,里面的鸽子数量大于1

我们设int的范围中最大的正数为(0111 1111 1111 1111 1111 1111 1111 1111)2=(21 4748 3647)10≈(2.1*10^9)2

假设有一个比int更大的数(99 9999 9999)10,则经过平方后得到9^2*10=810。因此[1, 99 9999 9999]范围内的数,经过平方后得到的数一定在[0, 810]的范围内,因此我们就有了810个鸽笼,假设最坏情况下一个属于[1, 99 9999 9999]数经过平方后得到1填充了一个笼,再次平方得到2填充第二个笼…一直到810个笼子全部填完(这里只是假设最坏情况,实际不太可能达到),则第811次平方后又得到了一个[0, 810]内的数,因此造成了循环。

那对于int范围内的数就更加会出现循环的情况了,毕竟int范围内的数平方得到的新数一定在[0, 810]的范围内,如果不循环,那么每一个数才放进小于810的笼子里根本不够用!

2.4.11. 盛最多水的容器

本题难度相较于前面会上升一些,首先最容易的解法就是:暴力穷举,直接上两个循环,枚举出所有的情况,找到最大的容积,但是使用这种方法一定会超时。

但是本题可以在遍历的时候作出节省,这是一种重要的思路:有的时候不得不使用枚举时,可以考虑是否剔除一些情况达到提高枚举效率的目的。

  1. 首先使用两个指针beginend指向数组heights[]的首尾处
  2. 计算高和宽height = min{heights[begin], heights[end]}width = end - begin,然后尾插到volumes
  3. 然后从heights[begin]heights[end]选择中最小的那一个数的下标begin++或者end--
  4. 只要满足begin < end就一直循环1~3即可
  5. 最后找到volumes中最大的体积返回即可
class Solution 
{
public:
    int maxArea(vector<int>& heights) 
    {
        int begin = 0, end = (int)heights.size() - 1;

        vector<int> volumes;
        
        int width = 0;
        int height = 0;
        while (begin < end)
        {
            //1.取得“最大的宽”
            width = end - begin;

            //2.取得“最小的高”
            height = heights[begin];
            if (height > heights[end])
            {
                height = heights[end--];
            }
            else
            {
                begin++;
            }
            //3.计算区间内最大面积
            volumes.push_back(width * height);
        }
        return *std::max_element(volumes.begin(), volumes.end());;
    }
};

时间复杂度是 O ( n ) O(n) O(n),由于是两个指针在遍历数组,因此就相当于遍历整个数组,因此数据复杂度就是 O ( n ) O(n) O(n)

空间复杂度是 O ( 1 ) O(1) O(1),这点没什么好解释的

2.5.611. 有效三角形的个数

一般而言,判断三个数abc能否构成三角形的依据是:
{ a + b > c a + c > b b + c > a \begin{cases} a+b>c\\ a+c>b\\ b+c>a \end{cases} a+b>ca+c>bb+c>a
但是,如果将abc三个数有序为a <= b <= c,就只需要判断一次a + b > c即可,因此就可以先把整个数组排序好后再来判断是否构成三角形。

因此暴力一点的话可以像下面这么写:

class Solution
{
    bool check(vector<int>& nums, int i, int j, int k)
    {
        return (nums[i] + nums[j] > nums[k]);
    }
public:
    int triangleNumber(vector<int>& nums)
    {
        sort(nums.begin(), nums.end());

        int count = 0;
        for (int i = 0; i < nums.size(); i++)
        {
            for (int j = i + 1; j < nums.size(); j++)
            {
                for (int k = j + 1; k < nums.size(); k++)
                {
                    if (check(nums, i, j, k))
                    {
                        count++;
                    }
                }
            }
        }
        return count;
    }
};

但是这只能过大部分的例子,还有一些情况没有办法过(数据量太大),因此还需要做优化。

首先数组已经是有序(具有单调性)的了,只需要判断a + b > c即可。

则从最后一个元素 x n x_{n} xn开始证明有 x 0 + x n − 1 > x n x_{0}+x_{n-1}>x_{n} x0+xn1>xn即可直接认为 x n − 2 x_{n-2} xn2后的数都可以和 x n − 1 x_{n-1} xn1以及 x n x_{n} xn构成三角形,无需判断…

class Solution
{
public:
    int triangleNumber(vector<int>& nums)
    {
        //1.排序数组
        sort(nums.begin(), nums.end());

        //2.通过三角形的性质结合单调性判断有多少种符合的情况
        int count = 0;//存储有多少种组合
        int key = nums.size() - 1, begin = 0, end = key - 1;//分为区间[begin, end]key
        while (key >= 2)
        {
            while (begin < end)
            {
                if (nums[begin] + nums[end] > nums[key])
                    //如果nums[begin] + nums[end] > key,
                    //那么nums[end]加上“nums[begin]...nums[end-1]”的任意一个数都大于key
                    //然后变成[begin, end--]key,也就是说:明确了和nums[end]结合有end - begin种情况
                {
                    count += (end - begin);
                    end--;
                }
                else//如果不是这样,那么就变成[begin++, end]key
                {
                    begin++;
                }
            }
            begin = 0;//最后重置一下左区间索引
            end = --key - 1;//最后重置一下右区间索引(并且修改key)
        }
        return count;
    }
};

时间复杂度: O ( n 2 ) O(n^{2}) O(n2)

2.6.LCR 179. 两数之和

这道题目也是利用单调性达到节省枚举次数的目的。

  1. 首先选定最后一个数price[end],和数组其他的数price[begin]相加
  2. 如果发现相加值等于目标值,则返回price[begin]price[end]
  3. 如果发现相加值小于目标值,则begin++
  4. 如果发现相加值大于于目标值,则说明不用继续移动begin了。因为此时的price[begin] + price[end] > target,那么根据单调性,price[begin~end-1] + price[end]都大于target。此时begin重置为0,然后end--,重复1~4步骤即可
class Solution
{
public:
    vector<int> twoSum(vector<int>& price, int target)
    {
        //1.创建要返回的顺序表
        vector<int> ret;

        //2.创建双指针begin和end
        int end = price.size() - 1;
        int begin = 0;

        //3.从最后一个指针开始循环,每次循环向前一步
        while (end != 0)
        {
            while (begin < end)
            {
                if (price[begin] + price[end] == target)//如果相等就找到了
                {
                    ret.push_back(price[begin]);
                    ret.push_back(price[end]);
                    return ret;
                }
                else if (price[begin] + price[end] < target)//如果小于就找比price[begin]更大的数
                {
                    begin++;
                }
                else//price[begin] + price[end] > target,这个时候已经大于目标值了,没有必要再循环让begin++了,直接跳出即可
                {
                    break;
                }
            }
            begin = 0;//重置begin
            end--;
        }
        return ret;
    }
};

或者简化为以下代码(上述代码还有些冗余):

class Solution
{
public:
    vector<int> twoSum(vector<int>& price, int target)
    {
        //1.创建要返回的顺序表
        vector<int> ret;

        //2.创建双指针begin和end
        int end = price.size() - 1;
        int begin = 0;

        //3.从最后一个指针开始循环,每次循环向前一步
        while (begin < end)
        {
            if (price[begin] + price[end] > target)//如果相等就找到了
            {
                end--;
            }
            else if (price[begin] + price[end] < target)//如果小于就找比price[begin]更大的数
            {
                begin++;
            }
            else
            {
                ret.push_back(price[begin]);
                ret.push_back(price[end]);
                break;
            }
        }

        return ret;
    }
};

时间复杂度:O(n)

2.7.LCR 007. 三数之和

class Solution
{
public:
    vector<vector<int>> threeSum(vector<int> nums)
    {
        //1.设置要返回的顺序表
        vector<vector<int>> ret;
        //2.排序原数据数组
        sort(nums.begin(), nums.end());
        //3.查找复合条件的三元组
        int n = nums.size();
        for (int i = 0; i < n; )
        {
            if (nums[i] > 0) break;

            int left = i + 1, right = n - 1, target = -nums[i];
            while (left < right)
            {
                int sum = nums[left] + nums[right];
                if (sum > target)
                {
                    right--;
                }
                else if (sum < target)
                {
                    left++;
                }
                else
                {
                    ret.push_back({ nums[i], nums[left], nums[right] });
                    left++, right--;

                    //去重
                    while (left < right && nums[left] == nums[left - 1]) left++;
                    while (left < right && nums[right] == nums[right + 1]) right--;
                }
            }
            i++;
            while (i < n && nums[i] == nums[i - 1]) i++;
        }
        return ret;
    }
};

这题比较难,以后再做然后补充。

时间复杂度: O ( n 2 ) O(n^{2}) O(n2)

2.8.18. 四数之和

class Solution
{
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target)
    {
        vector<vector<int>> ret;
        sort(nums.begin(), nums.end());

        int n = nums.size();
        for (int i = 0; i < n; )
        {
            for (int j = i + 1; j < n; )
            {
                int left = j + 1, right = n - 1;
                long long aim = (long long)target - nums[i] - nums[j];//防止溢出
                while (left < right)
                {
                    int sum = nums[left] + nums[right];
                    
                    if (sum < aim)
                    {
                        left++;
                    }
                    else if (sum > aim)
                    {
                        right--;
                    }
                    else
                    {
                        ret.push_back({ nums[i], nums[j], nums[left++], nums[right--] });
                        //去重
                        while (left < right && nums[left] == nums[left - 1]) left++;
                        while (left < right && nums[right] == nums[right + 1]) right--;
                    }
                }
                //去重
                j++;
                while (j < n && nums[j] == nums[j - 1]) j++;
            }
            //去重
            i++;
            while (i < n && nums[i] == nums[i - 1]) i++;
        }
        return ret;
    }
};

时间复杂度: O ( n ) = n 3 O(n) = n^{3} O(n)=n3

空间复杂度:主要消耗在排序那里

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

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

相关文章

求Top K问题

1.大小根堆解决Top k问题 传统思想&#xff1a;是将容器中的数据进行排序&#xff0c;排序的时间复杂度最差像冒泡是O(n^2),最好像快排是O(nlogn)。 如何在线性时间内O(n)找到Top K的元素呢? 相当于将原始序列遍历一遍就可以找到相应的元素&#xff0c;其实也没有必要将所有…

C语言之函数式宏

目录 函数和数据类型 函数式宏 函数和函数式宏 函数式宏和对象式宏 不带参数的函数式宏 函数式宏和逗号运算符 函数式宏和函数类似并且比函数更加灵活&#xff0c;下面我们就来学习函数式宏的相关内容。 函数和数据类型 我们来编写一个程序&#xff0c;它能计算出所读取…

python蓝桥杯的回形取数

#来源于蓝桥杯的训练 题号是用户登录https://www.lanqiao.cn/problems/1517/learning/?page1&first_category_id1&problem_id1517 根据题目描述可以知道&#xff0c;我们传入的是一个矩阵。 在这里我们使用列表来实现矩阵。 那么&#xff0c;我们直接看代码 dir …

超详细 | 黏菌算法原理、实现及其改进与利用(Matlab/Python)

测试函数为F15 在MATLAB中执行程序结果如下&#xff1a; 在Python中执行程序结果如下&#xff1a; 众所周知&#xff0c;麻雀搜索算法SSA是2020年由东华大学沈波教授团队提出[1]的一种性能十分优异的优化算法&#xff0c;而最近作者发现&#xff0c;在2020年还提出了一个优…

腾讯云:AI云探索之路

随着科技的飞速发展&#xff0c;人工智能(AI)云计算领域日益显现出其巨大的潜力和价值。在这个充满挑战和机遇的领域&#xff0c;腾讯云凭借其卓越的技术和创新能力&#xff0c;取得了令人瞩目的成果。本文将深入探讨腾讯云在AI云计算领域的优势&#xff0c;以及其为人工智能发…

Post Json数据与Form表单数据转换器

具体请访问&#xff1a;在线Json转Form表单参数工具

python绘制gif动图--避免收费拒绝水印

在cp源码解读-CSDN博客文章浏览阅读341次,点赞4次,收藏6次。coreutils:cp源代码分析https://blog.csdn.net/zhaiminlove/article/details/135026160中为了直观的表达文件是如何一步步的copy的,就想到了做一个gif,但是从来没弄过,一下有点麻爪了。 首先想到的是百度、Goog…

孩子都能学会的FPGA:第三十三课——用FPGA实现一个通用的SPI主机接收模块

&#xff08;原创声明&#xff1a;该文是作者的原创&#xff0c;面向对象是FPGA入门者&#xff0c;后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门&#xff0c;作者不光让大家知其然&#xff0c;还要让大家知其所以然&#xff01;每个工程作者都搭建了全自动化的仿…

C语言指针4

1. #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>int main() {int a 10;int* p &a;//一级指针int** pp &p;//二级指针return 0; }上述代码中p的类型是int* pp的类型是int** 2.int* arr[5]; 数组arr的每个元素是整形指针 3.定义一个变量时,去掉变…

报数游戏C语言

分析:掌握数字移动的规律&#xff0c;以及判断&#xff0c;我们可以用一个二维数组来记录每一个人说的数字&#xff0c;就像第一张图片一样&#xff0c;西安向右边移动&#xff0c;再向左下移动&#xff0c;再向左边移动&#xff0c;在向右边移动&#xff0c;在可以用一个数组来…

3 - Electron BrowserWindow对象 关于窗口

优雅的打开应用~ 当加载缓慢&#xff0c;打开应用的一瞬间会出现白屏&#xff0c;以下方法可以解决 const mainWindow new BrowserWindow({ show: false }) mainWindow.once(ready-to-show, () > {mainWindow.show() }) 设置背景颜色 const win new BrowserWindow({ b…

比特币即自由

号外&#xff1a;教链内参12.15《疯狂的铭文》 文 | Ross Ulbricht. 原文标题&#xff1a;Bitcoin Equals Freedom. 2019.9.25 在中本聪发明比特币后的头一年左右&#xff0c;发生了一些特别的事情&#xff0c;不仅没有人预料到&#xff0c;甚至很多人认为不可能。试着想象一下…

【Python从入门到进阶】44、Scrapy的基本介绍和安装

接上篇《43.验证码识别工具结合requests的使用》 上一篇我们学习了如何使用验证码识别工具进行登录验证的自动识别。本篇我们开启一个新的章节&#xff0c;来学习一下快速、高层次的屏幕抓取和web抓取框架Scrapy。 一、Scrapy框架的背景和特点 Scrapy框架是一个为了爬取网站数…

Python:Jupyter

Jupyter是一个开源的交互式计算环境&#xff0c;由Fernando Perez和Brian Granger于2014年创立。它提供了一种方便的方式来展示、共享和探索数据&#xff0c;并且可以与多种编程语言和数据格式进行交互。Jupyter的历史可以追溯到2001年&#xff0c;当时Fernando Perez正在使用P…

开源免费图床Lychee本地部署搭建个人云图床并公网访问【内网穿透】

文章目录 1.前言2. Lychee网站搭建2.1. Lychee下载和安装2.2 Lychee网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 图床作为图片集中存放的服务网站&#xff0c;可以看做是云存储的一部分&#xff0c;既可…

LeetCode(64)分隔链表【链表】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 分隔链表 1.题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示…

加油站“变身”快充站,探讨充电新模式——安科瑞 顾烊宇

摘要&#xff1a;新能源汽车规模化发展的同时&#xff0c;充电不便利的痛点愈发明显。在未来的新能源汽车行业发展当中&#xff0c;充电的矛盾要远远大于造车的矛盾&#xff0c;解决好充电的问题成为电动汽车行业发展的一个突出问题。解决充电补能问题&#xff0c;重要的方式之…

Python实现员工管理系统(Django页面版 ) 六

本篇博客主要实现用户账号管理&#xff0c;这与之前的账号管理不同&#xff0c;之前的账号管理你可以理解为公司在外面买的一些手机号然后需要发放给员工做内部使用&#xff0c;而本篇博客的用户账号管理主要是为了后续的登录网页实现&#xff0c;那么我们开始今天的项目实现吧…

栈和队列的实现(Java篇)

文章目录 一、栈的概念二、栈的实现2.1压栈(push)2.2出栈(pop)2.3获取栈顶元素(peek)2.4判断栈是否为空(isEmpty)栈的实现测试 三、队列的概念四、队列的实现4.1入队(offer)4.2出队(poll)4.3判断队列是否为空4.4获取对头元素队列的实现测试 五、循环队列5.1入队5.2出队5.3获取队…

手把手教你Linux查找Java的安装目录并设置环境变量以及Linux下执行javac未找到命令的保姆级教学

查找Java的安装目录 输入 java -version&#xff0c;查看是否成功安装Java 输入 which java&#xff0c;查看Java的执行路径 输入 ls -lrt /usr/bin/java 输入 ls -lrt /etc/alternatives/java&#xff0c;/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.el7_7.x86_64 就是J…