赞
踩
给定一个数组,求出其中连续的最大的和
数组 {1,-4,10,5,-10,23}, 求出当前数组中最大的和,10+5+ -10 +23 = 28
数组 {2,-10,4,9,-29,10}, 求出当前数组中最大的和,4+9=13
已知数组,想求出连续最大和,先初始化最大值为数组第一个数字;
然后循环数组一直相加求连续和,每加完一个值,就用连续和 和 最大值进行比较,从新赋值;
求连续和的过程中,如果出现负数,则清0,原因,负数和后一个相加,肯定没有0和后一个相加数字大;
public int getSum(int[] arr){
if(arr.length == 0)
return 0;
//用来记录最大和的值
int max = arr[1];
//用来记录数组连续和
int sum = 0;
for(int i : arr){
//计算 arr[0]+arr[1]+arr[2]+.... 出现负数归零
sum = Math.max(0,sum+i);
//比较 arr[0]+arr[1]+arr[2]+.... 和当前最大值谁大
max = Math.max(sum,max);
}
return max;
}
将一个整数进行反转输出
数字 1234,反转后为 4321;
数字 -1230,反转后为 -321;
整数反转,可能会带来一个问题,就是反转后的数字超过了int类型的最大或最小值,代码多加一行判断,这种情况暂时不考虑;
进行反转,符号保留,那就从被反转整数的最后一个数字开始计算,计算方式为取模的方式
public int reverse(int x){
//用来记录反转后的整数
int r = 0;
while(x != 0){
//x%10 取出原整数的最后一位数
//r*10 是为了将反转后的数进位 3变成30 31变成310
r = (r*10)+(x%10);
//原整数去掉最后一位数字
x/=10;
}
return r;
}
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数
数字 1234,从后向前读4321,不是回文数;
数字 12321,从后向前读也是 12321,这是个回文数;
数字 1221,从后向前读也是 1221,这是个回文数;
数字 -121,从后向前读也是 121-,不是回文数;
由回文数的本质可知,负数不能成文回文数,10的倍数不能成为回文数(10,40,3000);
判断回文数分为两种,一种是长度为偶数的整数,从中间分开,正好两边长度相同的数字去比较;
还有一种是长度为基数的,中间分开后,最中间的数据去掉,两边的数字去比较;
public boolean isPalindrome(int x) { if(x < 0 || (x != 0 && (x % 10) == 0)) return false; //记录反转后的数字 int r = 0; while(r < x){ //x%10 取出原整数的最后一位数 //r*10 是为了将反转后的数进位 3变成30 31变成310 r = (r*10)+(x%10); //原整数去掉最后一位数字 x/=10; } //x==r/10 是因为 121 这种奇数位数据,x最后结果为 12,除10 之后 变为1,在进行判断 return x==r ? true : false || x==r/10 ? true : false; }
给定一个有序数组,在当前数组中直接删除重复项,使每个元素只出现一次(删除并不准确,应为替换),并返回新数组长度
[1,2,2,3,4,4,5] 删除重复项后,原数组变为 [1,2,3,4,5,4,5] ,返回长度为 5(原数组前5个元素为新数组,且元素不重复);
[1,2,2,5] 删除重复项后,原数组变为 [1,2,5,5] ,返回长度为 3(原数组前3个元素为新数组,且元素不重复);
在原数组上直接做修改,是数组前面的元素不重复,后面的数据就不管了,然后返回前面不重复元素的个数;
数组是排好序的,
public int removeDuplicates(int[] nums) { if(nums == null || nums.length == 0){ //数组无元素的情况 return 0; } //数组的第一个元素,用于和后面的比较是否元素相等,如果不相等 int startNum = nums[0]; //替换后的数组长度,从第二个数组开始循环,所以新数组长度初始为1 int newLen = 1; //循环第一个元素肯定不会涉及重复问题,所以从第二个元素开始循环 for(int i=1;i<nums.length;i++){ if(nums[i] != startNum){ nums[newLen] = nums[i]; //新数组长度加1 newLen ++; //从新赋值,下一次比较重复元素使用 startNum = nums[i]; } } return newLen; }
一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 完美数。
给定一个 整数 n, 如果是完美数,返回 true,否则返回 false
输入6,能被28整除的整数有1、2、4、7、14,1+2+4+7+14=28,与输入数相同,返回true
输入15,能被15整除的整数有1、3、5,1+3+5 与输入数不同,返回false
通过题目可知,整数1的正因子只有它本身,所以输入1的情况直接返回false
所有正整数都可被1整除
一个数除被一个数整除,肯定也能被得出的商整除,6/2 =3,反正 6/3=2,所以整除时商和除数都是因子
整数除以最小的正因子,那么商就是它最大的正因子。
假设2位最小正因子。输入18, 18/2=9, 那么9就是18的最大因子(题目不包括自身,所以除数是2开始的)
class Solution { public boolean checkPerfectNumber(int num) { //等于1直接返回false if(num == 1) return false; //用来记录正因子之和,因为所有正整数都可被1整除,默认初始值为1 int total = 1; //记录因子的初始值,此处没用1,因为total默认为1了 int y = 2; //临时变量 int x = num; while(y < x){ //判断是否整除正因子 if(num % y == 0){ //能被整除的情况,记录当前除数和商的和 total = (total + y) + (num / y); //临时变量记录为当前的商,因为最大的因子只会是这个商 x = num / y; } y++; } return total == num; } }
一个仅包含小写英文字母和 ‘?’ 字符的字符串 s,请你将所有的 ‘?’ 转换为若干小写字母,使最终的字符串不包含任何 连续重复 的字符。
输入 ?zs,
返回 azs,该示例共有 25 种解决方案,从 "azs" 到 "yzs" 都是符合题目要求的。
只有 "z" 是无效的修改,因为字符串 "zzs" 中有连续重复的两个 'z' 。
输入ubv?w
返回ubvaw,该示例共有 24 种解决方案,只有替换成 "v" 和 "w" 不符合题目要求。
因为 "ubvvw" 和 "ubvww" 都包含连续重复的字符
如果输入的s==? ,可以直接返回任意一个字母
如果?在输入字符串的第一个或者最后一个位置,只需要比较前一个或者后一个字符就可,例如 ?a 和 a?
如果?在输入字符串的第一个或者最后一个位置,记录前一个或者后一个字符要判断是否会下标越界
class Solution { public static String modifyString(String s) { if(s.equals("?")) //输入的是字符串是问号,直接返回字母a return "a"; //将输入的字符串转换为char数组 char[] ss = s.toCharArray(); //循环转换的char数组 for(int index =0; index < ss.length;index++){ if(ss[index] != '?'){ //如果当前不是 ?直接下一次循环 continue; } //记录当前 ? 的前一个和后一个字符,默认给一个 * char start = '*',end = '*'; //如果当前 ? 处于第一个字符的位置,只需要比较后一个字符 if(index == 0 && s.length()-1 != index){ //记录后一个字符 end = ss[index + 1]; } //如果当前?处于最后一个字符的位置,只需要比较前一个字符 else if(index == s.length()-1 && index != 0){ //记录前一个字符 start = ss[index - 1]; } //如果当前?在字符串的中间位置,记录前后字符 else{ //记录前一个字符 和 后一个字符 start = ss[index - 1]; end = ss[index + 1]; } a: for(char ch = 'a';ch < 'z'; ch ++){ //循环a-z字母,判断前后字符都不等于当前循环的字母 if(ch != start && ch != end){ //将当前问号替换字母,并跳出当前循环 ss[index] = ch; break a; } } } return new String(ss); } }
给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/’ 开头),请你将其转化为更加简洁的规范路径
在 Unix 风格的文件系统中:一个点(.)表示当前目录本身;两个点 (…) 表示将目录切换到上一级(指向父目录);任意多个连续的斜杠(即,‘//’)都被视为单个斜杠 ‘/’ 。
输入/home/,返回 /home
目录最后的 / 可以省略不展示
输入/home//foo/,返回 /home/foo
路径中间的双斜杠,可以简化为单斜杠,并将最后的斜杠省略
输入/a/./b/../../c/,返回 /c
路径/a/.中的 (.),表示当前路径,也就是/a路径,所以路径变为/a/b/../../c/
路径/a/b/..中的(..)表示上级目录,所以路径变为/a/../c/
路径/a/..中的(..)表示上级目录,路径变为/c/,最终简化为/c
输入/home/../../..,返回 /
可以将路径用/分割成为一个数组,判断每一个元素,是否包括(.)或者(..),分别做不同的处理
创建一个数组(用栈更优),记录原路径数组循环时简化后的路径
长度为2倍的原路径分割的数组长度,因为原数组分割后的长度是不包含斜杠的了,但是优化的数组是要包含斜杠的
class Solution { public static String simplifyPath(String path) { //斜杠分割转数组 String[] arrPath = path.split("\\/"); //用于记录简化后的数据,长度*2是因为简化后的数据会包含 斜杠 String[] arr = new String[arrPath.length*2]; //用于记录记录简化后路径数组的已经使用的数组下标 int index = -1; //循环遍历数组中的元素 for(String str : arrPath){ //如果是. 指向当前目录,什么也不用干,进入下次循环; //如果是.. 并且下标为-1 虽然指向上一个目录,但是下标为-1说明还没有路径,什么也不用干,进入下次循环 if(str == null || "".equals(str) || ".".equals(str) || (index == -1 && "..".equals(str))){ //如果当前元素为空,则进入下次循环 continue; } if ("..".equals(str)){ //如果是.. 则指向上一个目录,删除最后一个路径已经路径前的斜杠,并将下标恢复 arr[index] = ""; arr[index-1] = ""; index -=2; }else{ //如果不是.. 不是. 则正常添加路径和路径前的斜杠,下标+2 arr[index+1] = "/"; arr[index+2] = str; index +=2; } } //记录最终的简化路径 StringBuilder sb = new StringBuilder(); for(String str :arr){ //如果出现一次空,就说明路径已经简化结束,直接退出循环即可 if(str == null|| "".equals(str)){ break; } //记录简化路径 sb.append(str); } //如果路径为空,直接返回斜杠 return sb.toString().equals("") ? "/" : sb.toString(); } }
一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。
如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false
注意:i,j,k 不用必须连续
输入[1,2,3,4,5],返回true:下标0,1,2位置的数字是一次递增的
输入[2,1,5,0,3],返回false: 不存在长度为3的递增子序列
输入[1,5,3,4],返回true: 下标0,2,3位置的数字是一次递增的
通过题目可知,数组长度如果小于3,那必然是返回false
思路:
先定位到序列的第一个数,可以让这个数默认等于数组的第一个数
序列的第二个数默认值为 最大整数,防止循环比较时,直接返回true
循环数组,判断当前循环的数和第一个数、第二个数的关系:
如果 第一个数 < 第二个数 < 当前数 ,return true
如果 第一个数 < 第二个数 && 第二个数 > 当前数 ,第二个数从新赋值
如果 第一个数 < 当前数,第一个数从新赋值
class Solution { public static boolean increasingTriplet(int[] nums) { //获取数组长度 int length = nums.length; if(length < 3){ //如果小于3,直接返回false return false; } //子序列第一个值,默认为数组第一个数字 int fir = nums[0]; //子序列第二个值,默认为最大整数 int sec = Integer.MAX_VALUE; //数组循环下标 int i = 1; while(i < length){ //循环的当前数值 int num = nums[i]; if(sec < num){ //如果第二个数,小于当前数,返回true. 因为第一个数,小于第二个数 return true; }else if(fir < num){ //进入这个条件,说明第一个条件没通过,就是前提条件为 第二个数,小于当前数 //第二个数,小于当前数 并且 第一个数小于当前数,就将当前数赋值给第二个数 sec = num; }else{ //进入这个条件,说明第一个数肯定是大于当前数的,将第一个数从新复制 fir = num; } //进入下一次循环 i++; } return false; } }
一个整数数组 nums ,其中总是存在 唯一的 一个最大整数 。
并且这个数 至少是数组中每个其他数字的两倍 。
如果是,则返回 最大元素的下标 ,否则返回 -1
输入[3,6,1,0],返回1:下标1位置的数字是最大,并且满足是数组中其他数字最少两倍的条件
输入[1,2,3,4],返回-1: 下标3位置的数字是最大,但是不满足条件,返回-1
输入[9],返回0: 不存在其他数字,默认为其他数字两倍
如果输入数组长度为1,那么直接返回0即可
先找出数组中最大的数字,这个最大的数字要和数组中其他数字的二倍进行比较大小,有这个可以得知:
我们用最大的数字,和第二大的数字的二倍比较大小就可以了
如果最大的数字比第二大的数字的二倍大,那就一定比其他的数字的二倍大
第二大的数字的二倍肯定也比其他数字的二倍大
class Solution { public static int dominantIndex(int[] nums) { if(nums.length == 1){ //数组长度为1,直接返回 return 0; } //数组前两个数字中,较大数字的下标 //用于存放最大数字的下标 int max = nums[0] > nums[1] ? 0 : 1; //数组前两个数字中,较小数字的下标 //用于存放第二大数字的下标 int prev = max == 0 ? 1 : 0; //因为上面已经取出来前两个下标的数,所以循环从第三个开始 for(int i =2;i<nums.length;i++){ if(nums[max] < nums[i]){ //判断最大数字小于当前这个数,那就把大数进行替换 prev = max; max = i; }else if(nums[prev] < nums[i]){ //判断最大数字大于当前这个数,并且第二大的数小于当前这个数,替换第二大的数字 prev = i; } } //判断最大数字否大于第二大数字的两倍 return nums[max] >= nums[prev] * 2 ? max : -1; } }
给定一个 24 小时制(小时:分钟 “HH:MM”)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
输入["23:59","00:00"],返回1,相差1分钟
输入["00:00","23:59","00:00"],返回0,有相同时间,相差分钟数为0
如果列表中,有两个相同时间,则直接返回0
如果输入列表的长度为 60分钟*24小时=1440个数据,那就说明必然会有重复数据,直接返回0
数据比较时间时,还要判断最大时间和最小时间的 24 小时差:
输入["00:00","01:00","23:50"] ,不止要正着比较 各个时间差,还要倒着比较
比如:00:00到和23:50,正着比较就是 23小时50分,但是倒着比较却只有10分钟
class Solution { public static int findMinDifference(List<String> timePoints) { //获取输入的集合长度 int timePointsLen = timePoints.size(); if (timePointsLen > 1440) { //如果长度大于1440,说明肯定会有重复的时间,直接返回 return 0; } //新创建一个数组,用于记录传过来的集合的分钟时 int[] timeMArr = new int[timePointsLen]; //循环传过来的集合 for(int i = 0;i < timePointsLen;i++){ //获取每一时间的值 String time = timePoints.get(i); //将时间换算成从0点到当前的分钟数,时乘60+分 例: 10:15 10*60+15 timeMArr[i] = Integer.valueOf(time.substring(0,2))*60 + Integer.valueOf(time.substring(3,5)); } //将时间分钟数的集合排序,排序后,分钟从小到大 Arrays.sort(timeMArr); //当前最小的时间,初始化为第二个和第一个分钟数的差 int min = timeMArr[timePointsLen-1] - timeMArr[timePointsLen-2]; //循环记录分钟数的数组 for(int len =1;len < timePointsLen ;len++){ //判断后一个分钟和前一个分钟的差,和默认的时间差进行比较,取最小 min = Math.min(timeMArr[len] - timeMArr[len-1],min); if(min == 0){ //如果出现两个时间的差等于0的情况,直接返回0 return min; } } //倒着比较最小和最大的两个时间的差,加1440就是加24小时的分钟数 int m = timeMArr[0] + 1440 - timeMArr[timePointsLen-1]; //输出最小的 return min > (m) ? m : min; } }
一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j
满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false
nums = {1,2,3,1}, k=3, 返回true。下标0和下标3的数字相同并且abs(0-3)<=k
nums = [1,0,1,1], k = 1, 返回true。下标2和下标3的数字相同并且abs(2-3)<=k
nums = [1,2,3,1,2,3], k = 2, 返回false。存在下标相等的数字,但是下标差的绝对值>k
可以使用map来记录每个数字出现的下标位置
循环数组,当发现map中已经出现了当前的数字,说明此时已经满足了题目的 nums[i] == nums[j] 条件
发现满足 nums[i] == nums[j] 条件时,只需要在判断 abs(i - j) <= k 条件是否成立
public static boolean containsNearbyDuplicate(int[] nums, int k) { //存放每个数据出现位置 Map<Integer,Integer> map = new HashMap<>(); //循环数组 for(int i = 0;i<nums.length;i++){ //当前循环出的数字 Integer num = nums[i]; //用当前数字,从map中取出出现在位置 Integer index = map.get(num); if(index != null && i - index <= k ){ //map中存在当前数字,并且上次记录的下标和这次出现的下标差<=k,直接返回true return true; }else{ //map中不存在当前数字,或者下标已经不符合条件了,添加记录 map.put(num,i); } } return false; }
把给定的字符串 S 从左到右写到每一行上,每一行的最大宽度为100个单位,如果在写某个字母的时候会使这行超过了100 个单位,那么应该把这个字母写到下一行。
给定了一个数组 widths ,这个数组 widths[0] 代表 ‘a’ 需要的单位, widths[1] 代表 ‘b’ 需要的单位,…, widths[25] 代表 ‘z’ 需要的单位。
现在回答两个问题:至少多少行能放下S,以及最后一行使用的宽度是多少个单位?将答案作为长度为2的整数列表返回。
widths =[90,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,40]
S = "azz"
输出: [2, 80]
解释:
字符串'a'在数组下标第一个位置,也就是长度为90,'z'的长度为40,因为一行的宽度为100,所以‘a’自己在一行,'zz'另起一行,总共2行,第二行为‘zz’宽度为80
字符串从左到右写到每一行上
每一行宽度不能超过100,写字符时如果宽度超过100,当前字符另起一行
字符串中每一个字符的宽度,在数组中有对应,字符‘a’‘b’‘c’‘d’,分别对应数组中0,1,2,3的下标,以此类推,‘z’在数组中最后的一个元素
public int[] numberOfLines(int[] widths, String S) {
int[] ans = new int[2];
int l = 0,r = 1;
for(int i=0;i<S.length();i++){
l += widths[S.charAt(i)-'a'];
if(l > 100){
r += 1;
l = widths[S.charAt(i)-'a'];
}
}
ans[0] = r;
ans[1] = l;
return ans;
}
还会持续更新一些常见得面试算法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。