今日三道笔试题(字节跳动)
1.(leetcode第2题,两链表求和)
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode result = new ListNode(0); //将a和b分别初始化为列表l1和l2的头部 ListNode a = l1,b = l2; ListNode current = result; int carry = 0;//进位 int sum = 0; //每对节点计算的和 //思路:依次从头节点相加(每对节点相加),如果相加超过10,则进位加1,进行下一节点的计算。(每次计算都加上进位) while(a != null || b != null){ //如果一个节点为空就将此节点的值设为0 int x = a == null ? 0 : a.val; int y = b == null ? 0 : b.val; sum = x + y + carry; carry = sum / 10;//更新进位 current.next = new ListNode(sum % 10); //进行下一节点计算 current = current.next; if(a != null) a = a.next; if(b != null) b = b.next; } //如果计算到最后有进位,记得再链接上进位 if(carry > 0){ current.next = new ListNode(carry); } return result.next; } }
2.(回溯法,深度优先搜索遍历)
题目描述: 输入一个二维字符数组map和一个字符串数组word,搜索word是否在map中。搜索的定义是从map的任意位置开始,可以上下左右移动,依次和word每个字符匹配,如果word能匹配完,则存在,否则不存在。
注:map中的每个位置只能被访问一次。
acdz
xtro
fiwo
如上述map,“zoo”能搜到,“wto”不能搜索到。
输入描述:
第一行三个整数 n,m,q,n和m表示map的长度和宽度,q表示询问的数量。 接下来n行,每行包含一个长度为m的字符串。 接下来q行,每行包含一个字符串,表示询问该字符串是否能在map中找到。
输出描述:
对于每个询问字符串,如果能找到,输出“Has”,否则输出“Not Has”,注意加上“Case”以及查询编号,编号从0开始。
实例:
输入:
3 4 5
aaaa
abaa
aaaa
aa
ba
ab
bb
cb
输出:
Case 0:Has Case 1:Has Case 2:Has Case 3:Not Has Case 4:Not Has
解题思路:本题使用回溯法,深度优先搜素遍历二维字符数组中的元素,寻找可能存在的路径。
代码如下:
import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()){ int n = sc.nextInt(); //二维数组map的长度 int m = sc.nextInt(); //二维数组map的宽度 int q = sc.nextInt(); //询问的数量 char[][] map = new char[n][m]; for(int i = 0; i < n; i++){ map[i] = sc.next().toCharArray(); } //接下来q行,每行一个word,进行处理 for(int i = 0; i < q; i++){ String word = sc.next(); if(helper(map, word)){ System.out.println("Case " + i + ":" + "Has"); }else{ System.out.println("Case " + i + ":" + "Not Has"); } } } }
/*算法处理*/ public static boolean helper(char[][] arr, String word){ int row = arr.length; int clown = arr[0].length; //用一个数组表示某个位置上的元素是否已经使用过 boolean[] flag = new boolean[row*clown]; //从每个位置开始遍历看是否包含此字符串。 for(int i = 0; i < row; i++){ for(int j = 0; j < clown; j++){ if(helper(arr, word, i, j, flag, 0)){ return true; } } } return false; } //index为word的第index位 public static boolean helper(char[][] arr, String word, int i,int j, boolean[] flag, int index){ //当index等于Word的最后一个位置,也就是前面匹配都成功了,可以返回true。 if(index == word.length()) return true; if(i < 0 || i >= arr.length || j < 0 || j >= arr[0].length || arr[i][j] != word.charAt(index) || flag[i * arr[0].length + j]) return false; //符合要求后,表示当前字符与字符串中对应字符相等,将该字符标记为使用过,再去判断剩下的字符。 flag[i * arr[0].length + j] = true; //递归上下左右判断字符是否匹配 if(helper(arr, word, i-1, j, flag, index+1) || helper(arr, word, i+1, j, flag, index+1) ||helper(arr, word, i, j-1, flag, index+1) ||helper(arr, word, i, j+1, flag, index+1)){ return true; } //如果后面的不匹配,就得把当前的标志清除返回。注意一定要清! flag[i*arr[0].length+j]=false; return false; } }
3.(积水问题)
给定一个一维数组,每个元素表示一个海拔高度。下雨之后低洼的地方会积水。假设雨水足够,能填满所有的低洼地方,计算下雨后所有低洼地段的总蓄水量。
例如给定数组2、5、1、2、3、4、7、2,下雨后,各个地方算上雨水会被填充为2、5、5、5、5、5、7、2,一共填充了10个单位的雨水。
输入描述:
第一行一个整数N,表示数组长度。N<=1e6
第二行N个整数,表示N个海拔高度。每个高度不超过1e6
输出描述:
输出一个数字
示例:
输入:
5
5 2 1 4 3
输出:5
解题思路:积水面积=砖和水面积-砖面积
砖面积比较好求(直接数组元素相加即可),主要求砖和水面积:从两侧最小值开始计算,遇上更大的开始递归
代码:
import java.util.Scanner; public interface BrickAndWater { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()){ int n = sc.nextInt(); //数组长度 int[] nums = new int[n]; for(int i = 0; i < n; i++){ nums[i] = sc.nextInt(); } System.out.println(water(nums)); } } /*积水面积=砖和水总面积-砖面积*/ public static int water(int[] nums){ if(nums.length < 3) return 0; //砖面积 int brickSum = 0; for(int i = 0; i < nums.length; i++){ brickSum += nums[i]; } //积水面积=砖和水总面积-砖面积 return fill(nums, 0, nums.length - 1) - brickSum; } /*求砖和水总面积*/ public static int fill(int[] nums, int start, int end){ int sum = 0; //从两侧最小值开始计算 if(nums[start] <= nums[end]){ int temp = nums[start]; sum += temp; for(int i = start + 1; i <= end; i++){ //如果下一个砖比前面的高,就递归处理下一个 if(nums[i] > temp){ sum += fill(nums, i, end); break; }else{ //如果下一个砖比前一个低,低的地方会有积水,因为是从最小值的一端开始,所以积水的高度就为前一个砖的高度 sum += temp; } } }else{ int temp = nums[end]; sum += temp; for(int i = end - 1; i >= start; i--){ if(nums[i] > temp){ sum += fill(nums, start, i); break; }else{ sum += temp; } } } return sum; } }