14.面试算法-字符串常见算法题(三)

news2024/11/14 18:38:31

1. 字符串回文问题

1.1 LeetCode.125. 验证回文串

回文问题在链表中是重点,在字符串中同样是个重点。当初我去美团面试第一轮技术面的第一个算法题就是让写判断字符串回文的问题。

这个本身还是比较简单的,只要先转换成字符数组,然后使用双指针方法从两头到中间比较就行了。也许是过于简单了吧,面试时经常被加餐,例如LeetCode里的两道题。 一个是普通的验证回文串,第二个是找最长的子回文串。第二个问题需要动态规划等技术,有点难度,如果感兴趣可以自行去了解下,这里先看一下基本的。

题目:

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个回文串。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是回文串 ,返回 true ;否则,返回 false 。

示例1:
输入 : “A man, a plan, a canal: Panama” 输出 : true
解释: “amanaplanacanalpanama” 是回文串
示例2:
输入 : “race a car” 输出 : false
解释: “raceacar” 不是回文串
示例 3:
输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 “” 。
由于空字符串正着反着读都一样,所以是回文串。

分析

最简单的方法是对字符串 s 进行一次遍历,并将其中的字母和数字字符进行保留,放在另一个字符串 sgood 中。这样我们只需要判断 sgood 是否是一个普通的回文串即可。

判断的方法有两种。第一种是使用语言中的字符串翻转 API 得到 sgood 的逆序字符串 sgood_rev,只要这两个字符串相同,那么 sgood 就是回文串。

class Solution {
    public boolean isPalindrome(String s) {
        StringBuffer sgood = new StringBuffer();
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char ch = s.charAt(i);
            if (Character.isLetterOrDigit(ch)) {
                sgood.append(Character.toLowerCase(ch));
            }
        }
        StringBuffer sgood_rev = new StringBuffer(sgood).reverse();
        return sgood.toString().equals(sgood_rev.toString());
    }
}

第二种是使用双指针。初始时,左右指针分别指向 sgood 的两侧,随后我们不断地将这两个指针相向移动,每次移动一步,并判断这两个指针指向的字符是否相同。当这两个指针相遇时,就说明 sgood 时回文串。

class Solution {
    public boolean isPalindrome(String s) {
        StringBuffer sgood = new StringBuffer();
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char ch = s.charAt(i);
            if (Character.isLetterOrDigit(ch)) {
                sgood.append(Character.toLowerCase(ch));
            }
        }
        int n = sgood.length();
        int left = 0, right = n - 1;
        while (left < right) {
            if (Character.toLowerCase(sgood.charAt(left)) != Character.toLowerCase(sgood.charAt(right))) {
                return false;
            }
            ++left;
            --right;
        }
        return true;
    }
}

2. 字符串简单搜索问题

我们为什么叫简单搜索问题呢?因为字符串的有些搜索问题非常复杂,需要dp或者更高级的算法,例如字符匹配等等,因此这里我们先看几个简单的情况。

2.1 LeetCode387. 字符串中的第一个唯一字符

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

示例 1:
输入: s = “leetcode”
输出: 0
示例 2:
输入: s = “loveleetcode”
输出: 2
示例 3:
输入: s = “aabb”
输出: -1

提示:s 只包含小写字母

我们可以对字符串进行两次遍历,在第一次遍历时,我们使用哈希映射统计出字符串中每个字符出现的次数。在第二次遍历时,我们只要遍历到了一个只出现一次的字符,那么就返回它的索引,否则在遍历结束后返回 -1。

class Solution {
    public int firstUniqChar(String s) {
        Map<Character, Integer> frequency = new HashMap<Character, Integer>();
        for (int i = 0; i < s.length(); ++i) {
            char ch = s.charAt(i);
            frequency.put(ch, frequency.getOrDefault(ch, 0) + 1);
        }
        for (int i = 0; i < s.length(); ++i) {
            if (frequency.get(s.charAt(i)) == 1) {
                return i;
            }
        }
        return -1;
    }
}

2.2 LeetCode58. 最后一个单词的长度

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

示例 1:
输入:s = “Hello World”
输出:5
解释:最后一个单词是“World”,长度为 5。
示例 2:
输入:s = " fly me to the moon "
输出:4
解释:最后一个单词是“moon”,长度为 4。
示例 3:
输入:s = “luffy is still joyboy”
输出:6
解释:最后一个单词是长度为 6 的“joyboy”。

分析
这个题还是比较简单的,反向遍历。题目要求得到字符串中最后一个单词的长度,可以反向遍历字符串,寻找最后 一个单词并计算其长度。

由于字符串中至少存在一个单词,因此字符串中一定有字母。首先找到字符串中的最后一个字母,该字母即为最后一个单词的最后一个字母。

从最后一个字母开始继续反向遍历字符串,直到遇到空格或者到达字符串的起始位置。遍历到的每个字母都是最后一个单词中的字母,因此遍历到的字母数量即为最后一个单词的长度。

class Solution {
    public int lengthOfLastWord(String s) {
        int index = s.length() - 1;
        while (s.charAt(index) == ' ') {
            index--;
        }
        int wordLength = 0;
        while (index >= 0 && s.charAt(index) != ' ') {
            wordLength++;
            index--;
        }
        return wordLength;
    }
}

3. 旋转和重排

3.1 [剑指Offer】 58. 左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例1:
输入 : s = “abcdefg”, k = 2
输出 : “cdefgab”
示例2:
输入 : s = “lrloseumgh”, k = 6
输出 : “umghlrlose”

本题有多种方式处理的,最直观的方式是前面剪贴下来的若干字符和后面的字符保存到两个数组里,然后再按照要求合并就行了。这个在go、JavaScript 、python等语言中有切片的操作,可以非常方便地处理,java中虽然没有切片,但是可以通过子串来实现相同的功能。

class Solution {
	public String reverseLeftWords(String s, int n) { 
		if (s == null || s.length() == 0) {
			return s;
		}
		return s.substring(n, s.length()) + s.substring(0, n);
	}
}

第二种方式是通过StringBuilder来实现拼接,先将第k个之后的元素添加进来,然后再将前k个添加进来,代码如下:

class Solution {
	public String reverseLeftWords(String s, int n) { 
		if (s == null || s.length() == 0) {
			return s;
		}
		StringBuilder res = new StringBuilder();
		for(int i = n; i < s.length(); i++)
			res.append(s.charAt(i));
		for(int i = 0; i < n; i++)
			res.append(s.charAt(i));
		return res.toString();
	}
}

很明显上面两个都需要记住StringBuilder等的用法,如果使用最简单的String和char数组来处理怎么做呢?前面我们已经介绍过,所以这里只要看一下就明确了:

class Solution {
	public String reverseLeftWords(String s, int n) { 
		if (s == null || s.length() == 0) {
			return s;
		}
		String res = "";
		for(int i = n; i < s.length(); i++)
			res += s.charAt(i);
		for(int i = 0; i < n; i++)
			res += s.charAt(i);
		return res;
	}
}

3.2 判定是否互为字符重排

给定两个字符串 s1s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。

示例1:
输入 : s1 = “abcadfhg”, s2 = “bcafdagh” ’
输出 : true
示例2:
输入 : s1 = “abc”, s2 = “bad”
输出 : false

这个题第一眼看,感觉是个排列组合的题目,然后如果使用排列的算法来处理,难度会非常大,而且效果还不一定好。用简单的方式就能解决。

第一种方法:将两个字符串全部从小到大或者从大到小排列,然后再逐个位置比较,这时候不管两个原始字符串是什么,都可以判断出来。

代码也不复杂:

public boolean checkPermutation(String s1, String s2) { 
	// 将字符串转换成字符数组
	char[] s1Chars = s1.toCharArray(); 
	char[] s2Chars = s2.toCharArray();
	// 对字符数组进行排序
	Arrays.sort(s1Chars); 
	Arrays.sort(s2Chars);
	// 再将字符数组转换成字符串,比较是否相等
	return new String(s1Chars).equals(new String(s2Chars));
}

注意这里我们使用了Arrays.sort(),你是否记得我们在数组一章提到过这个方法必须牢记。

第二种方法:使用Hash,注意这里我们不能简单的存是否已经存在,因为字符可能在某个串里重复存在例如"abac"。我们可以记录出现的次数,如果一个字符串经过重新排列后,能够变成另外一个字符串,那么它们的每个不同字符的出现次数是相同的。如果出现次数不同,那么表示两个字符串不能够经过重新排列得到。

这个代码逻辑不复杂,但是写起来稍微长一点:

class Solution {
	public boolean checkPermutation(String s1, String s2) {
		if (s1.length() != s2.length()) {
			return false;
		}
		char[] s1Chars = s1.toCharArray();
		Map<Character, Integer> s1Map = getMap(s1);
		Map<Character, Integer> s2Map = getMap(s2);
		for (char s1Char : s1Chars) {
			if (!s2Map.containsKey(s1Char) 
				|| s2Map.get(s1Char) != s1Map.get(s1Char)) {
				return false;
			}
		}
		return true;
	}

	// 统计指定字符串str中各字符的出现次数,并以Map的形式返回
	private Map<Character, Integer> getMap(String str) {
		Map<Character, Integer> map = new HashMap<>();
		char[] chars = str.toCharArray();
		for (char aChar : chars) {
			map.put(aChar, map.getOrDefault(aChar, 0) + 1);
		}
		return map;
	}
}

拓展

这个题还有一种方法,就是不管原始字符串有多长,是什么,基本元素都是26个英文字母,只少不多,那么我们可以换个思维:为两个字符串分别建立两个大小为26的字母表数组,每个位置是对应的字母出现的次数。最后统计一下两个数组的字母数和每个字母出现的次数就可以了。

这种方法其实也是文本搜索引擎的基本思想,例如 elasticSearch等,在文本搜索里有个专门的名字,叫“倒排索引”。看一下实现代码:

public class Solution {
	public boolean CheckPermutation(String s1, String s2) {
		if (s1.length() != s2.length()) {
			return false;
		}
		int[] c1 = count(s1);
		int[] c2 = count(s2);
		for (int i = 0; i < c1.length; i++) {
			if (c1[i] != c2[i]) {
				return false;
			}
		}
		return true;
	}

	private int[] count(String str) {
		int[] c = new int[26];
		char[] chars = str.toCharArray();
		for (char aChar : chars) {
			c[aChar - 'a']++;
		}
		return c;
	}
}

4. 最长公共前缀

这是一道经典的字符串问题,先看题目要求:

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 “”。

示例1:
输入:strs = [“flower”,“flow”,“flight”]
输出: “fl”
示例2:
输入:strs = [“dog”,“racecar”,“car”]
输出: “”
解释:输入不存在公共前缀。

要解答这个问题,我们需要先看一下公共前缀的分布有什么特点,如下图:
在这里插入图片描述
可以看到,第一种方式,我们可以竖着比较,如左图所示,每前进一个位置就比较各个串,看是不是都是相等的,只要在某一轮遇到一个不相等的,那么就结束。

第二种方式,还可以横着比较,先比较前两个找到公共前缀fix1,然后再和第三个比较公共前缀得到fix2,我们可以确定fix2一定不会比fix1更长,然后和第四个比较,得到fix4,一直到最后一个fixn。每次得到的fix都不会比前面的长,最后比较完了还剩下的就是需要找的前缀了。

看到这里你是否有种似曾相识的感觉,我们前面合并K个数组或者K个链表不也是类似的思路吗?是的,就是类似的思路。

第三种方式,我们是否可以对第二种进行优化一下,借鉴归并的思想,先两两一组找fix,然后将找到的fix再两两归并呢?当然可以了,这就是归并的方式。

先看第一种的实现方法,竖着比较。纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,如果不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。

class Solution {
	public String longestCommonPrefix(String[] strs) { 
		if (strs == null || strs.length == 0) {
			return "";
		}
		int length = strs[0].length();
		int count = strs.length;
		for (int i = 0; i < length; i++) {
			char c = strs[0].charAt(i);
			for (int j = 1; j < count; j++) {
				if (i == strs[j].length() || strs[j].charAt(i) != c) {
					return strs[0].substring(0, i);
				}
			}
		}
		return strs[0];
	}
}

第二种是横着依次比较,依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀(其实就是看是否要缩短,一定不会变长),当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。

如果在尚未遍历完所有的字符串时,最长公共前缀已经是空串,则最长公共前缀一定是空串,因此不需要继续遍历剩下的字符串,直接返回空串即可。

class Solution {
	public String longestCommonPrefix(String[] strs) { 
		if (strs == null || strs.length == 0) {
			return "";
		}
		String prefix = strs[0];
		int count = strs.length;
		for (int i = 1; i < count; i++) {
			prefix = longestCommonPrefix(prefix, strs[i]);
			if (prefix.length() == 0) {
				break;
			}
		}
		return prefix;
	}

	public String longestCommonPrefix(String str1, String str2) {
		int length = Math.min(str1.length(), str2.length());
		int index = 0;
		while (index < length && str1.charAt(index) == str2.charAt(index)) {
			index++;
		}
		return str1.substring(0, index);
	}
}

再看第三种,归并方法,这种方式也可以叫分治,就是先两两判断,之后再两两比较,直到得到最终的结果。

class Solution {
	public String longestCommonPrefix(String[] strs) { 
		if (strs == null || strs.length == 0) {
			return "";
		} else {
			return longestCommonPrefix(strs, 0, strs.length - 1);
		}
	}

	public String longestCommonPrefix(String[] strs, int start, int end) {
		if (start == end) {
			return strs[start];
		} else {
			int mid = (end - start) / 2 + start;
			String lcpLeft = longestCommonPrefix(strs, start, mid);
			String lcpRight = longestCommonPrefix(strs, mid + 1, end);
			return commonPrefix(lcpLeft, lcpRight);
		}
	}

	public String commonPrefix(String lcpLeft, String lcpRight) {
		int minLength = Math.min(lcpLeft.length(), lcpRight.length());
		for (int i = 0; i < minLength; i++) {
			if (lcpLeft.charAt(i) != lcpRight.charAt(i)) {
				return lcpLeft.substring(0, i);
			}
		}
		return lcpLeft.substring(0, minLength);
	}
}

5. 字符串压缩问题

这个题也是出现频率很高的题目,经常在面经中看到。实现起来略有难度,我们一起看一下。

题目要求

给你一个字符数组 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” 替代。

这个题貌似采用双指针策略来处理就行,但是再分析发现三个指针才够。

我们可以使用两个指针分别标志我们在字符串中读和写的位置,还要一个指针left用来标记重复字段的开始位置。read指针不断向前读取,每次当读指针read 移动到某一段连续相同子串的最右侧,我们就在写指针 write 处依次写入该子串对应的字符和子串长度即可。

当读指针read位于字符串的末尾,或读指针read指向的字符不同于下一个字符时,我们就认为读指针read 位于某一段连续相同子串的最右侧。该子串对应的字符即为读指针 read 指向的字符串。我们使用变量 left 记录该子串的最左侧的位置,这样子串长度即为 read-left+1。

这里还有一个问题,就是长度可能超过10,因此还要实现将数字转化为字符串写入到原字符串的功能。这里我们采用短除法将子串长度倒序写入原字符串中,然后再将其反转即可。

class Solution {
    public int compress(char[] chars) {
        int n = chars.length;
        int write = 0, left = 0;
        for (int read = 0; read < n; read++) {
            if (read == n - 1 || chars[read] != chars[read + 1]) {
                chars[write++] = chars[read];
                int num = read - left + 1;
                if (num > 1) {
                    int anchor = write;
                    while (num > 0) {
                        chars[write++] = (char) (num % 10 + '0');
                        num /= 10;
                    }
                    reverse(chars, anchor, write - 1);
                }
                left = read + 1;
            }
        }
        return write;
    }

    public void reverse(char[] chars, int left, int right) {
        while (left < right) {
            char temp = chars[left];
            chars[left] = chars[right];
            chars[right] = temp;
            left++;
            right--;
        }
    }
}

6. 总结

我们介绍了很多字符串的基本题目,这些题目在面试现场写代码时经常会遇到。可以看到这些题目的处理方式与数组问题一脉相承,在数组里经常用的双指针也可以使用。但是因为字符串本身的特殊性,又要做很多特殊的处理,例如空格等等。

另外很多字符串的问题必须先将字符串转换成数组才能处理,这需要我们对charAt()等方法非常熟悉才可以。很多人会在简历里写 “精通java基础开发”,但是如果String的用法都忘了,甚至现场问面试官官,你还觉得自己精通吗?

字符串有很多经典,但是比较难的题目,这个难在需要使用回溯、动态规划等方法来处理,此等问题更适合在高级算法中介绍。例如最长回文串和字符串匹配等等。我们在后续的动态规划再研究。

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

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

相关文章

PS相关操作记录

1. 磨皮步骤 1.1. 图层操作 先对照片进行去瑕疵、液化等操作&#xff0c;操作完的图层&#xff0c;重命名为液化&#xff0c;方便识别。复制两个图层&#xff0c;分别改为“低频”、“高频”&#xff0c;低频在下&#xff0c;高频在上。选中“低频”图层&#xff0c;滤镜 -&g…

NodeJs文档

文件操作 // 1. 导入fs模块 const fs require(fs)文件写入 //异步写入 // fs.writeFile(文件名&#xff0c; 待写入的数据&#xff0c; 选项设置&#xff08;可选&#xff09;&#xff0c; 回调函数) fs.writeFile(./座右铭.txt, 三人行&#xff0c;必有我师傅, err > {/…

kubernetes应用的包管理Helm工具

目录 一、helm简介 二、部署helm 1、官网与资源 2、部署helm &#xff08;1&#xff09;安装helm &#xff08;2&#xff09;配置helm命令补齐 三、helm常用操作 &#xff08;1&#xff09;查询官方应用中心 &#xff08;2&#xff09;管理第三方repo源 &#xff08;…

AI周报(9.15-9.21)

AI应用-宇宙建筑师&#xff1a;AI探索宇宙结构 近日&#xff0c;来自马克斯普朗克研究所等机构&#xff0c;利用宇宙学和红移依赖性对宇宙结构形成进行了场级仿真。 AI版“宇宙闪电侠”&#xff1a;若以传统宇宙模拟的缓慢行进比作悠然自得的蜗牛&#xff0c;那么AI便宛如宇宙…

centos7 添加中文字体

一、打开C:\Windows\Fonts 复制 复制出来再拷贝到linux服务器目录&#xff1a;/usr/share/fonts/jtwin #执行 #mkdir /usr/share/fonts/jtwin chmod -R 755 /usr/share/fonts/jtwin yum -y install ttmkfdir ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir 编辑&…

Ubuntu 安装和使用 Fcitx 中文输入法;截图软件flameshot

一、Ubuntu 安装和使用 Fcitx 中文输入法 在 Ubuntu 上安装和使用 Fcitx 输入法框架是一个常见的选择&#xff0c;特别是对于需要中文输入的用户。以下是详细的步骤来安装和配置 Fcitx 输入法&#xff1a; 1. 安装 Fcitx 和相关输入法 首先&#xff0c;更新你的包列表并安装…

黑马智数Day1

src文件夹 src 目录指的是源代码目录&#xff0c;存放项目应用的源代码&#xff0c;包含项目的逻辑和功能实现&#xff0c;实际上线之后在浏览器中跑的代码就是它们 apis - 业务接口 assets - 静态资源 &#xff08;图片&#xff09; components - 组件 公共组件 constants…

1.量化第一步,搭建属于自己的金融数据库!

数据是一切量化研究的前提。 做量化没有数据&#xff0c;就相当于做饭时没有食材。 很多时候&#xff0c;我们需要从大量的数据中寻找规律&#xff0c;并从中开发出策略。如果我们每次使用的时候&#xff0c;都从网上去找数据&#xff0c;一方面效率低下&#xff0c;另一方面短…

erlang学习:Linux常用命令2

目录操作命令 对目录进行基本操作 相关cd切换目录之类的就直接省去了&#xff0c;以下操作中都会用到 查看当前目录下的所有目录和文件 ls 列表查看当前目录下的所有目录和文件&#xff08;列表查看&#xff0c;显示更多信息&#xff09; ls -l 或 ll 在当前目录下创建一个…

中断-MCU

中断 目录 中断 中断的概念 中断的执行过程 中断服务函数 中断的部分专业术语 – 了解 STM32中的中断分类 嵌套向量中断控制器 NVIC STM32中的中断优先级 中断编程 外部中断&#xff08;单片机之外&#xff09;之EXTI中断 相关寄存器 外部中断&#xff08;EXTI&am…

在jupyter notebook中取消代理服务器的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

2.个人电脑部署MySQL,傻瓜式教程带你拥有个人金融数据库!

2.个人电脑部署MySQL&#xff0c;傻瓜式教程带你拥有个人金融数据库&#xff01; ‍ 前边我们提到&#xff0c;比较适合做量化投研的数据库是MySQL&#xff0c;开源免费。所以今天我就写一篇教程来教大家如何在自己的环境中部署MySQL。 在不同的设备或系统中安装MySQL的步骤…

MySQL篇(存储过程 触发器 存储函数)(持续更新迭代)

目录 一、存储过程 1. 简介 2. 特点 3. 语法 3.1. 创建 3.2. 调用 3.3. 查看 3.4. 删除 4. 示例 二、变量 1. 简介 2. 系统变量 2.1. 查看系统变量 2.2. 设置系统变量 2.3. 演示示例 3. 用户定义变量 3.1. 赋值 方式一 方式二 3.2. 使用 3.3. 演示示例 4.…

MES系统能够实时监控生产进度,优化生产排程

一、MES系统实时监控生产进度 MES系统通过集成各种数据采集手段&#xff08;如RFID、条形码、传感器、PLC等&#xff09;&#xff0c;能够实时、准确地采集生产现场的数据&#xff0c;包括设备状态、生产数量、生产时间、人员操作等信息。这些数据被实时传输到MES系统的数据库…

群晖使用Docker部署WPS Office并实现异地使用浏览器制作办公文档

文章目录 前言1. 本地环境配置2. 制作本地分享链接3. 制作公网访问链接4. 公网ip地址访问您的分享相册5. 制作固定公网访问链接 前言 想象一下这个场景&#xff1a;如果遇到周末紧急需要改方案&#xff0c;但团队成员都在各自家中&#xff0c;这个时候如果大家能够轻松访问这个…

照片EXIF数据统计与可视化

拍的照片越来越多&#xff0c;想要了解一下日常拍摄的习惯&#xff0c;便于后面换镜头、调整参数等操作&#xff0c;所以写了这个脚本来统计照片的EXIF数据。该脚本用于统计指定文件夹下所有JPG图片的EXIF数据&#xff0c;包括快门速度、ISO、焦距、光圈和拍摄时间&#xff0c;…

网络资源模板--Android Studio 仿WeChat聊天App

目录 一、项目演示 二、项目测试环境 三、项目详情 四、完整的项目源码 一、项目演示 网络资源模板--仿微信聊天App 二、项目测试环境 三、项目详情 登陆注册 ### 登录功能&#xff08;LoginActivity&#xff09; 1. **界面初始化**&#xff1a;设置界面元素&#xff0c;包…

二叉树---java---黑马

二叉树 遍历 遍历分两种 广度优先遍历 尽可能先访问距离根节点最近的节点&#xff0c;也称之为层序遍历。 深度优先遍历 对于二叉树&#xff0c;进一步分为三种 pre-order前序遍历&#xff0c;对于每一颗子树&#xff0c;先访问该节点&#xff0c;然后是左子树&#xf…

银河麒麟桌面操作系统如何添加WPS字体

银河麒麟桌面操作系统如何添加WPS字体 1、使用场景2、操作方法步骤一&#xff1a;下载字体文件步骤二&#xff1a;打开终端步骤三&#xff1a;进入字体文件所在目录步骤四&#xff1a;拷贝字体文件到WPS字体目录步骤五&#xff1a;更新字体缓存步骤六&#xff1a;重启WPS Offic…

C++ 把字符串转换成整数 (atoi) - 力扣(LeetCode)

点击链接即可查看&#xff1a;LCR 192. 把字符串转换成整数 (atoi) - 力扣&#xff08;LeetCode&#xff09; 一、题目 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 my…