华为OD高频面试题-手撕代码(完)
最短超串
总体思路: 用一个map集合记录small中所有元素 在窗口内的出现次数,用count记录窗口内的种类数, 如果种类数和small的长度相等 (因为small没有重复元素,种类数就是它的长度), 那么就更新结果,并且left右移。 1、创建一个空的哈希表 sMap 用于存储 small 数组中的元素及其出现的次数。 初始化计数器 count 为 0,用于记录当前窗口中包含了多少个 small 数组中的元素。 初始化滑动窗口的左边界 left 和右边界 right,初始值都为 0。 2、遍历 big 数组: 从左到右依次遍历 big 数组中的元素。 对于每个元素,如果它在 sMap 中存在,则更新计数器 count 和对应元素的计数值。 3、滑动窗口操作:当 count 等于 small 数组的长度时,表示当前窗口包含了 small 数组中的所 有元素,此时开始收缩窗口。 在收缩窗口的过程中,不断更新最小区间的长度 res 以及对应的左右索引值 l 和 r。 收缩窗口的条件是:当 left 指向的元素在 sMap 中存在,并且当前元素在窗口中的计数值等于 1 时, 将 count 减 1,表示当前窗口已不包含该元素。 4、返回结果:如果 res 的值大于 big 数组的长度,则说明不存在符合条件的最小区间,返回空数 组。 否则返回最小区间的左右索引值 l 和 r。 这种算法利用了滑动窗口的思想,在遍历 big 数组的过程中不断调整窗口的大小,最终找到了符合条件 的最小区间。 import java.util.*; public class Main { public static int[] func(int[] big, int[] small) { if (big.length == 0 || small.length == 0) { return new int[0]; } Map<Integer, Integer> sMap = new HashMap<>(); for (int i = 0; i < small.length; i++) { sMap.put(small[i], 0); } int count = 0; int left = 0; int right = 0; int res = big.length + 100; //记录最小区间长度 int l = 0; //记录最小区间的左索引值 int r = 0; //记录最小区间的右索引值 while (right < big.length) { int tmp = big[right]; right++; if (sMap.containsKey(tmp)) { if (sMap.get(tmp) == 0) { count++; } sMap.put(tmp, sMap.get(tmp) + 1); } while (count == small.length && left < right) { if (res > right - left) { res = right - left; l = left; r = right - 1; } if (sMap.containsKey(big[left])) { if (sMap.get(big[left]) == 1) { count--; } sMap.put(big[left], sMap.get(big[left]) - 1); } left++; } } return res > big.length ? new int[0] : new int[]{l, r}; } public static void main(String[] args) { int[] big = {7, 5, 9, 0, 2, 1, 3, 5, 7, 9, 1, 1, 5, 8, 8, 9, 7}; int[] small = {1, 5, 9}; int[] res = func(big, small); for (int item : res) { System.out.print(item + " "); } } }
快乐数
/*通过获取数字的每一个数位 求得下一个数字的值 根据题意来说 要么变成1 要么死循环 感觉这是一个环形问题 不然完全不知道会循环多少次 那么环形问题就可以用快慢指针的方式来判断是否成环 如果成环就说明陷入死循环了 那么fast一次走两步 slow一次走一步 那么两个指针一定会相遇 那么循环就会结束 以次来判断是否成环*/ class Solution { public static boolean isHappy(int n) { int fast = n; int slow = n; do{ slow = bitSquareSum(slow); fast = bitSquareSum(fast); fast = bitSquareSum(fast); }while(fast != slow); return fast == 1; } public static int bitSquareSum(int n){ int sum = 0; while(n > 0){ int bit = n % 10; sum += bit * bit; n = n / 10; } return sum; } public static void main(String[] args) { System.out.println(isHappyNum(19)); System.out.println(isHappyNum(2)); } } //使用集合的方式实现 public class Main { public static boolean isHappyNum(int n) { Set<Integer> set = new HashSet<>(); do { int tmp = calc(n); if (set.contains(tmp)) { return false; } set.add(tmp); n = tmp; } while (n != 1); return true; } public static int calc(int n) { int sum = 0; while (n > 0) { int bit = n % 10; sum += bit * bit; n = n / 10; } return sum; } public static void main(String[] args) { System.out.println(isHappyNum(19)); System.out.println(isHappyNum(2)); } }
对包含字母数字的字符串按规则排序
import java.util.*; /*思路: 1、先把数字,大写字母,小写字母分别取出来,放到三个集合中 2、分别对三个结合进行升序排序 3、遍历原字符数组, 遇到数字就从数字数组中获取第一个字符,更新到原字符数组中 遇到字母优先放入小写字母,然后把小写字母删除掉 等小写字母放完后,再放大写字母 4、最后将字符数组转成字符串返回即可 题目意思: 1、数字的相对位置不能变化,对所有数字进行升序排序 2、大小写字母位置也不能发生变化,小写字母升序排序后再排序大写字母 所以把数字,大写字母,和小写字母分别存储起来 然后排序,再拼接会字符串中就可以了*/ public class Main { public static void main(String[] args) { String str = "a2CB1c"; System.out.println(sort(str)); String str1 = "ab12C4Ac3B"; System.out.println(sort(str1)); } private static String sort(String str) { char[] chs = str.toCharArray(); List<Character> upper = new ArrayList<>(); List<Character> digit = new ArrayList<>(); List<Character> lower = new ArrayList<>(); for (int i = 0; i < chs.length; i++) { if (chs[i] >= '0' && chs[i] <= '9') { digit.add(chs[i]); } else if(chs[i] >= 'a' && chs[i] <= 'z') { lower.add(chs[i]); }else{ upper.add(chs[i]); } } Collections.sort(upper); Collections.sort(digit); Collections.sort(lower); for (int i = 0; i < chs.length; i++) { if (chs[i] >= '0' && chs[i] <= '9') { chs[i] = digit.get(0); digit.remove(0); } else{ if(!lower.isEmpty()){ chs[i] = lower.get(0); lower.remove(0); }else{ chs[i] = upper.get(0); upper.remove(0); } } } StringBuilder sb = new StringBuilder(); for (int i = 0; i <chs.length ; i++) { sb.append(chs[i]); } return sb.toString(); } }
找到最大周长的多边形
题目:
给你一个长度为 n 的 正 整数数组 nums 。
多边形 指的是一个至少有 3 条边的封闭二维图形。多边形的 最长边 一定 小于 所有其他边长度之
和。
如果你有 k (k >= 3)个 正 数 a1,a2,a3, …,ak 满足 a1 <= a2 <= a3 <= … <= ak 且
a1 + a2 + a3 + … + ak-1 > ak ,那么 一定 存在一个 k 条边的多边形,每条边的长度分别为
a1 ,a2 ,a3 , …,ak 。
一个多边形的 周长 指的是它所有边之和。
请你返回从 nums 中可以构造的 多边形 的 最大周长 。如果不能构造出任何多边形,请你返回 -1
。
示例 1:
输入:nums = [5,5,5]
输出:15
解释:nums 中唯一可以构造的多边形为三角形,每条边的长度分别为 5 ,5 和 5 ,周长为 5 + 5
+ 5 = 15 。
示例 2:
输入:nums = [1,12,1,2,5,50,3]
输出:12
解释:最大周长多边形为五边形,每条边的长度分别为 1 ,1 ,2 ,3 和 5 ,周长为 1 + 1 + 2
+ 3 + 5 = 12 。
我们无法构造一个包含变长为 12 或者 50 的多边形,因为其他边之和没法大于两者中的任何一个。
所以最大周长为 12 。
示例 3:
输入:nums = [5,5,50]
输出:-1
解释:无法构造任何多边形,因为多边形至少要有 3 条边且 50 > 5 + 5 。
提示:
3 <= n <= 10^5
1 <= nums[i] <= 10^9
import java.util.*; public class Main { //O(n) public static int getRes(int[] nums) { Arrays.sort(nums); int sum = Arrays.stream(nums).sum(); for (int i = nums.length - 1; i > 1; i--) { if (sum > nums[i] * 2) { return sum; } sum -= nums[i]; } return -1; } public static void main(String[] args) { int[] nums = {5, 5, 5}; System.out.println(getRes(nums)); int[] nums1 = {1, 12, 1, 2, 5, 50, 3}; System.out.println(getRes(nums1)); int[] nums2 = {5, 5, 50}; System.out.println(getRes(nums2)); } }
6个数找最大时间
思路: 1、首先要处理下小时的两位数 小时的第一位不能超过2,23 小时的第二位不能超过4 所以先去数组中查找小于3的最大值,确定小时的第一位 再去数组中查找小于4的最大值,确定小时的第二位 两个数字要在数组中删除掉 2、然后再去判断分钟 分钟的第一位不能超过6 分钟的地位为不能超过10 同1原理 3、再去确定秒 秒和分钟的判断差不多 import java.util.*; public class Main { public static void main(String[] args) { int[] data = {0, 2, 3, 0, 5, 6}; System.out.println(getRes(data)); int[] data1 = {1, 5, 6, 3, 4, 5}; System.out.println(getRes(data1)); } /** * 解题思路: 时间格式第一位不能大于2,第二位不能大于3等 * 所以从头开始,一位一位找,先找满足第一位的集合中的数字,然后找出最大的一个, * 碰到任何不满足条件的直接返回 invalid,满足则从数组从移除,以此类推 */ private static String getRes(int[] data) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < data.length; i++) { list.add(data[i]); } String s = "invalid"; String c = ":"; StringBuilder res = new StringBuilder(); //第一位不能大于3,获取数组中小于3的数字中最大的一个 int d1 = getPos(list, 3); if (d1 != -1) { list.remove(Integer.valueOf(d1)); res.append(d1); } else { return s; } //如果第一位是2,那么第二位则不能超过4 if (res.charAt(0) == '2') { //第二位 Integer d2 = getPos(list, 4); if (d2 != -1) { // 按照元素删除 list.remove(Integer.valueOf(d2)); res.append(d2); res.append(c); } else { return s; } // 否则,第一位可能是0或者1,这样第二位可以是0-9,即小于10 } else { //第二位 Integer d3 = getPos(list, 10); if (d3 != -1) { list.remove(d3); res.append(d3); res.append(c); } else { return s; } } //第三位,分钟最大是59,即小于6 int d4 = getPos(list, 6); if (d4 != -1) { list.remove(Integer.valueOf(d4)); res.append(d4); } else { return s; } //第四位,0-9 int d5 = getPos(list, 10); if (d5 != -1) { list.remove(Integer.valueOf(d5)); res.append(d5); res.append(c); } else { return s; } //第五位 int d6 = getPos(list, 6); if (d6 != -1) { list.remove(Integer.valueOf(d6)); res.append(d6); } else { return s; } //最后一位 if (getPos(list, 10) != -1) { res.append(getPos(list, 10)); } else { return s; } return res.toString(); } /** * 获取数组中比 val 小的数字中最大的一个数,没有返回-1 */ private static int getPos(List<Integer> list, int val) { return list.stream().filter(x -> x < val).mapToInt(x -> x).max().orElse(-1); } }
逆波兰表达式求值
/* 具体思路如下: 总体思路就是利用栈来模拟计算过程, 遇到操作符时从栈中取出操作数进行相应的计算, 然后将计算结果再次入栈,直到整个表达式遍历完为止, 最终栈中只会有一个元素,即为计算结果。 1、创建一个整型类型的栈 st,用于存储数字。 2、遍历输入的 tokens 数组,依次处理每个元素。 如果当前元素是操作符("+"、"-"、"*"、"/"), 则从栈中弹出两个操作数进行相应的运算,并将结果重新压入栈中。 如果当前元素是数字(非运算符),则将其转换为整型并压入栈中。 3、最终栈中只会剩下一个元素,即为计算结果,将其弹出并返回。*/ public class od_online { public static int getRes(String[] tokens) { Stack<Integer> st = new Stack<>(); for (int i = 0; i < tokens.length; i++) { if ("+".equals(tokens[i])) { int t1 = st.pop(); int t2 = st.pop(); st.push(t1 + t2); } else if ("-".equals(tokens[i])) { int t1 = st.pop(); int t2 = st.pop(); st.push(t2 - t1); } else if ("*".equals(tokens[i])) { int t1 = st.pop(); int t2 = st.pop(); st.push(t1*t2); } else if ("/".equals(tokens[i])) { int t1 = st.pop(); int t2 = st.pop(); st.push(t2 / t1); } else { st.push(Integer.valueOf(tokens[i])); } } return st.pop(); } public static void main(String[] args) { String tokens[] = {"2", "1", "/"}; System.out.println(getRes(tokens)); } }
跳跃游戏3
public class od_online { /* 使用深度优先搜索算法实现。 1、首先判断当前位置是否越界或者已经被访问过 (如果访问过用-1表示——,如果是则返回false。 2、然后判断当前位置的值是否为0,如果是则返回true。 3、接下来记录当前位置的值,并将该位置标记为已访问(改成-1)。 4、使用递归方式,分别从当前位置向前和向后进行跳跃, 判断是否能到达目标位置。如果任意一个方向可以到达,则返回true。 如果都无法到达,并返回false。 这个题意就是: 从给定的位置开始向前或者向后找,能不能 遇到0,如果可以返回真,否则返回假 所有就从当前的位置开始递归向前向后找 只有向前向后任意一个遇到0就可以返回了 */ public static boolean dfs(int[] arr, int i) { if (i < 0 || i >= arr.length || arr[i] == -1) { return false; } if (arr[i] == 0) { return true; } int backup = arr[i]; arr[i] = -1; boolean res = dfs(arr, backup + i) || dfs(arr, i - backup); return res; } public static void main(String[] args) { int arr[] = {4, 2, 3, 0, 3, 1, 2}; int start = 5; System.out.println(dfs(arr, start)); } }
早餐组合
/*思路: 1、首先,对 staple 和 drinks 数组进行排序。 这是因为在求解满足条件的组合数时, 排序可以帮助我们更有效地使用二分查找。 2、遍历staple数组中的所有元素,然后再 drinks数组中查找 drinks[mid] <= x - item 最大索引位置 3、使用二分查找在drinks数组中查找符合drinks[mid] <= val的值 的最大索引位置,它的返回值是 left,即第一个大于 val 的位置 4、最后将下标位置返回,并累加就是组合的结果 5、最后,返回 res % 1000000007,确保结果在取模后不会溢出, 并符合题目要求。 */ public class od_online { public static int bSearch(int[] arr, int val) { int left = 0; int right = arr.length; while (left < right) { int mid = left + (right - left) / 2; if (arr[mid] <= val) { left = mid + 1; } else if (arr[mid] > val) { right = mid; } } return left; } public static int breakfastNumber(int[] staple, int[] drinks, int x) { Arrays.sort(staple); Arrays.sort(drinks); long res = 0; for (int item : staple) { if (item > x) { break;//如果i直接大于x了就可以直接退出循环了 } else { res += bSearch(drinks, x - item); } } return (int) (res % 1000000007); } public static void main(String[] args) { int[] staple = {10, 20, 5}; int[] drinks = {5, 5, 2}; int x = 15; System.out.println(breakfastNumber(staple,drinks,x)); } }
工作级
乘积计算
#include <stdio.h> #include <stdlib.h> #include <string.h> int MaxProduct(const char *numStr) { int max = 0; for (size_t pos = 0; pos < strlen(numStr) - 1; pos++) { char s1[10] = {0}; char s2[10] = {0}; strncpy(s1, numStr, pos + 1); strncpy(s2, numStr + 1 + pos, strlen(numStr) - 1 - pos); int product = atoi(s1) * atoi(s2); if(max < product){ max = product; } } return max; } int main() { char numStr[] = "33333"; printf("%d\n", MaxProduct(numStr)); return 0; }
区间中位和
#include <stdio.h> #include <stdlib.h> #include <string.h> int cmp(const int *a, const int *b) { return *a - *b; } static int GetMedianSum(const int *numbers, size_t numbersSize) { int ret = 0; for (int size = 1; size <= numbersSize; ++size) { for (int idx = 0; idx + size <= numbersSize; ++idx) { int array[size]; memcpy(array, numbers + idx, sizeof(int) * size); qsort(array, size, sizeof(size), cmp); if (size % 2 == 0) { ret += array[size / 2 - 1]; } else { ret += array[size / 2]; } } } return ret; } int main() { int nums[] = {1, 5, 7, 4}; int size = sizeof(nums) / sizeof(int); printf("%d", GetMedianSum(nums, size)); }
定时器系统
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> typedef struct { int time; int timerId; } ResultInfo; typedef struct { int now; int *time; int *begin; int *status; size_t size; } TimerSystem; static TimerSystem *TimerSystemCreate(const int *timers, size_t timersSize) { TimerSystem *sys = (TimerSystem *) malloc(sizeof(TimerSystem)); size_t tmp = sizeof(int) * timersSize; sys->now = 0; sys->begin = (int *) malloc(tmp); memset(sys->begin, 0, tmp); sys->status = (int *) malloc(tmp); memset(sys->status, 0, tmp); sys->time = (int *) malloc(tmp); memcpy(sys->time, timers, tmp); sys->size = timersSize; return sys; } static bool TimerSystemTimerStart(TimerSystem *sys, int timerId) { if (timerId < 0 || timerId >= sys->size) { return false; } sys->begin[timerId] = sys->now; sys->status[timerId] = 1; return true; } static bool TimerSystemTimerStop(TimerSystem *sys, int timerId) { if (timerId < 0 || timerId >= sys->size) { return false; } sys->begin[timerId] = sys->now; sys->status[timerId] = 2; return true; } static int Compare(const ResultInfo *a1, const ResultInfo *a2) { if (a1->time == a2->time) { return a1->timerId - a2->timerId; } return a1->time - a2->time; } static ResultInfo *TimerSystemRunTimerSystem(TimerSystem *sys, int nowTime, size_t *returnValSize) { int len = 0; *returnValSize = 0; for (int i = 0; i < sys->size; ++i) { if (sys->status[i] == 1) { len += (nowTime - sys->begin[i]) / sys->time[i]; } } if (len == 0) { sys->now = nowTime; return NULL; } ResultInfo *res = (ResultInfo *) malloc(sizeof(ResultInfo) * len); int resSize = 0; for (int i = 0; i < sys->size; ++i) { if (sys->status[i] == 1) { int val = (nowTime - sys->begin[i]) / sys->time[i]; for (int j = 1; j <= val; ++j) { res[resSize].timerId = i; res[resSize].time = sys->begin[i] + sys->time[i] * j; resSize++; } sys->begin[i] += sys->time[i] * val; } } sys->now = nowTime; qsort(res, resSize, sizeof(ResultInfo), Compare); *returnValSize = resSize; return res; } static void TimerSystemFree(TimerSystem *sys) { if (sys->status != NULL) { free(sys->status); } if (sys->time != NULL) { free(sys->time); } if (sys != NULL) { free(sys); } } void test01() { int arr[] = {3, 5}; int size = 2; TimerSystem *sys = TimerSystemCreate(arr, size); printf("%d\n", TimerSystemTimerStart(sys, 0)); printf("%d\n", TimerSystemTimerStart(sys, 1)); size_t returnSize = 0; ResultInfo *res = TimerSystemRunTimerSystem(sys, 15, &returnSize); for (int i = 0; i < returnSize; ++i) { printf("%d %d\n", res[i].time, res[i].timerId); } printf("%d\n", TimerSystemTimerStop(sys, 1)); returnSize = 0; res = TimerSystemRunTimerSystem(sys, 20, &returnSize); for (int i = 0; i < returnSize; ++i) { printf("%d %d\n", res[i].time, res[i].timerId); } printf("%d\n", TimerSystemTimerStop(sys, 1)); printf("%d\n", TimerSystemTimerStop(sys, 2)); } void test02() { int arr[] = {8, 4, 11}; int size = 3; TimerSystem *sys = TimerSystemCreate(arr, size); size_t returnSize = 0; ResultInfo *res = TimerSystemRunTimerSystem(sys, 2, &returnSize); for (int i = 0; i < returnSize; ++i) { printf("%d %d\n", res[i].time, res[i].timerId); } printf("%d\n", TimerSystemTimerStart(sys, 1)); printf("%d\n", TimerSystemTimerStart(sys, 4)); res = TimerSystemRunTimerSystem(sys, 8, &returnSize); for (int i = 0; i < returnSize; ++i) { printf("%d %d\n", res[i].time, res[i].timerId); } printf("%d\n", TimerSystemTimerStart(sys, 0)); printf("%d\n", TimerSystemTimerStart(sys, 2)); printf("%d\n", TimerSystemTimerStart(sys, 1)); res = TimerSystemRunTimerSystem(sys, 20, &returnSize); for (int i = 0; i < returnSize; ++i) { printf("%d %d\n", res[i].time, res[i].timerId); } printf("%d\n", TimerSystemTimerStop(sys, 1)); returnSize = 0; res = TimerSystemRunTimerSystem(sys, 30, &returnSize); for (int i = 0; i < returnSize; ++i) { printf("%d %d\n", res[i].time, res[i].timerId); } } int main() { setbuf(stdout, NULL); test01(); // test02(); return 0; }