需要开通vip的题目暂时跳过
点击链接可跳转到所有刷题笔记的导航链接
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。
解答
public int hammingDistance(int x, int y) {
return Integer.bitCount(x^y);
}
分析
给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。
解答
public int minMoves2(int[] nums) {
Arrays.sort(nums);
int res = 0;
for(int i = 0;i < nums.length;i++){
res += Math.abs(nums[nums.length/2] - nums[i]);
}
return res;
}
分析
给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域。
网格中的格子水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
解答
int res = 0;
public int islandPerimeter(int[][] grid) {
int row = grid.length;
if(row == 0)return res;
int col = grid[0].length;
if(col == 0)return res;
boolean flag = false;
for (int i = 0; i < row; i++) {
if (flag) break;
for (int j = 0; j < col; j++) {
if (grid[i][j] == 1) {
int[][] visited = new int[row][col];
dfs(grid, i, j, visited);
flag = true;
break;
}
}
}
return res;
}
public void dfs(int[][] grid, int i, int j, int[][] visited) {
visited[i][j] = 1;
res += calEdgeLen(grid, i, j);
if (i > 0 && grid[i - 1][j] == 1 && visited[i - 1][j] == 0) dfs(grid, i - 1, j, visited);
if (i < grid.length - 1 && grid[i + 1][j] == 1 && visited[i + 1][j] == 0) dfs(grid, i + 1, j, visited);
if (j > 0 && grid[i][j - 1] == 1 && visited[i][j - 1] == 0) dfs(grid, i, j - 1, visited);
if (j < grid[0].length - 1 && grid[i][j + 1] == 1 && visited[i][j + 1] == 0) dfs(grid, i, j + 1, visited);
}
public int calEdgeLen(int[][] grid, int i, int j) {
int res = 0;
if (i == 0) res++;
if(i == grid.length - 1) res++;
if (j == 0) res++;
if(j == grid[0].length - 1) res++;
if (i > 0 && grid[i - 1][j] == 0) res++;//上
if (i < grid.length - 1 && grid[i + 1][j] == 0) res++;//下
if (j > 0 && grid[i][j - 1] == 0) res++;//左
if (j < grid[0].length - 1 && grid[i][j + 1] == 0) res++;//右
return res;
}
分析
在 “100 game” 这个游戏中,两名玩家轮流选择从 1 到 10 的任意整数,累计整数和,先使得累计整数和达到或超过 100 的玩家,即为胜者。
如果我们将游戏规则改为 “玩家不能重复使用整数” 呢?
例如,两个玩家可以轮流从公共整数池中抽取从 1 到 15 的整数(不放回),直到累计整数和 >= 100。
给定一个整数 maxChoosableInteger (整数池中可选择的最大数)和另一个整数 desiredTotal(累计和),判断先出手的玩家是否能稳赢(假设两位玩家游戏时都表现最佳)?
你可以假设 maxChoosableInteger 不会大于 20, desiredTotal 不会大于 300。
解答
public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
if (maxChoosableInteger >= desiredTotal) return true;
if ((1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal) return false; //1,..maxChoosable数列总和都比目标和小
int[] state = new int[maxChoosableInteger + 1]; //state[1]=1表示1被选了
return backtraceWitMemo(state, desiredTotal, new HashMap<String, Boolean>());
}
private boolean backtraceWitMemo(int[] state, int desiredTotal, HashMap<String, Boolean> map) {
String key = Arrays.toString(state); //这里比较关键,如何表示这个唯一的状态,例如[2,3]和[3,2]都是"0011",状态一样
if (map.containsKey(key)) return map.get(key); //如果已经记忆了这样下去的输赢结果,记忆是为了防止如[2,3],[3,2]之后的[1,4,5,..]这个选择区间被重复计算
for (int i = 1; i < state.length; i++){
if (state[i] == 0){ //如果这个数字i还没有被选中
state[i] = 1;
//如果当前选了i已经赢了或者选了i还没赢但是后面对方选择输了
if (desiredTotal - i <= 0 || !backtraceWitMemo(state, desiredTotal - i, map)) {
map.put(key, true);
state[i] = 0; //在返回之前回溯
return true;
}
//如果不能赢也要记得回溯
state[i] = 0;
}
}
//如果都赢不了
map.put(key, false);
return false;
}
分析
把字符串 s 看作是“abcdefghijklmnopqrstuvwxyz”的无限环绕字符串,所以 s 看起来是这样的:"…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd…".
现在我们有了另一个字符串 p 。你需要的是找出 s 中有多少个唯一的 p 的非空子串,尤其是当你的输入是字符串 p ,你需要输出字符串 s 中 p 的不同的非空子串的数目。
注意: p 仅由小写的英文字母组成,p 的大小可能超过 10000。
解答
//方法1
public int findSubstringInWraproundString(String p) {
if(p.equals("") || p == null)return 0;
int w = 1;
int ans = 0;
Map<Character,Integer> map = new HashMap<>();
map.put(p.charAt(0),1);
for(int i = 1;i < p.length();i++){
char cur = p.charAt(i);
if(cur - p.charAt(i-1) == 1 || cur - p.charAt(i-1) == -25)
w++;
else w = 1;
map.put(cur,Math.max(map.getOrDefault(cur,0) ,w));
}
for(Character c : map.keySet()){
ans += map.get(c);
}
return ans;
}
//方法2
public int findSubstringInWraproundString(String p){
int[] dp = new int[26];
int cnt = 1, n = p.length();
char[] cs = (" " + p).toCharArray();
for(int i = 1; i <= n; i++){
int idx = cs[i] - 'a';
if(check(cs[i - 1], cs[i])) cnt++;
else cnt = 1;
dp[idx] = Math.max(dp[idx], cnt);
}
int ans = 0;
for(int i = 0; i < 26; i++) ans += dp[i];
return ans;
}
public boolean check(char a, char b){
if(a == 'z' && b == 'a') return true;
return b - a == 1;
}
分析
提交结果
编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。
如果是有效的 IPv4 地址,返回 “IPv4” ;
如果是有效的 IPv6 地址,返回 “IPv6” ;
如果不是上述类型的 IP 地址,返回 “Neither” 。
IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (: 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。
解答
//方法1
import java.util.regex.Pattern;
class Solution {
String chunkIPv4 = "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
Pattern pattenIPv4 =
Pattern.compile("^(" + chunkIPv4 + "\\.){3}" + chunkIPv4 + "$");
String chunkIPv6 = "([0-9a-fA-F]{1,4})";
Pattern pattenIPv6 =
Pattern.compile("^(" + chunkIPv6 + "\\:){7}" + chunkIPv6 + "$");
public String validIPAddress(String IP) {
if (IP.contains(".")) {
return (pattenIPv4.matcher(IP).matches()) ? "IPv4" : "Neither";
}
else if (IP.contains(":")) {
return (pattenIPv6.matcher(IP).matches()) ? "IPv6" : "Neither";
}
return "Neither";
}
}
//方法2
public String validateIPv4(String IP) {
String[] nums = IP.split("\\.", -1);
for (String x : nums) {
if (x.length() == 0 || x.length() > 3) return "Neither";
if (x.charAt(0) == '0' && x.length() != 1) return "Neither";
for (char ch : x.toCharArray()) {
if (! Character.isDigit(ch)) return "Neither";
}
if (Integer.parseInt(x) > 255) return "Neither";
}
return "IPv4";
}
public String validateIPv6(String IP) {
String[] nums = IP.split(":", -1);
String hexdigits = "0123456789abcdefABCDEF";
for (String x : nums) {
if (x.length() == 0 || x.length() > 4) return "Neither";
for (Character ch : x.toCharArray()) {
if (hexdigits.indexOf(ch) == -1) return "Neither";
}
}
return "IPv6";
}
public String validIPAddress(String IP) {
if (IP.chars().filter(ch -> ch == '.').count() == 3) {
return validateIPv4(IP);
}
else if (IP.chars().filter(ch -> ch == ':').count() == 7) {
return validateIPv6(IP);
}
else return "Neither";
}
分析
提交结果
已有方法 rand7 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10 生成 1 到 10 范围内的均匀随机整数。
不要使用系统的 Math.random() 方法。
解答
public int rand10() {
int row,col,index;
do{
row = rand7();
col = rand7();
index = col + (row - 1) * 7;
}while(index > 40);
return 1 + (index - 1) % 10;
}
分析
给定一个不含重复单词的列表,编写一个程序,返回给定单词列表中所有的连接词。
连接词的定义为:一个字符串完全是由至少两个给定数组中的单词组成的。
解答
class Solution {
public List<String> findAllConcatenatedWordsInADict(String[] words) {
TrieNode root = new TrieNode();
for (String word : words) {
if (!word.equals("")) { //非空字符串添加到字典树中
root.add(word);
}
}
List<String> res = new ArrayList<>();
for (String word : words) {
if (dfs(word.toCharArray(), 0, root)) {
res.add(word);
}
}
return res;
}
private boolean dfs(char[] str, int start, TrieNode root) {
int n = str.length;
TrieNode node = root;
for (int i = start; i < n; i++) {
if (!node.next.containsKey(str[i])) {
return false;
}
node = node.next.get(str[i]);
if (node.isWord && dfs(str, i + 1, root)) {
return true;
}
}
return node.isWord && start != 0; //start != 0 不能匹配自己
}
}
class TrieNode {
public boolean isWord;
public Map<Character, TrieNode> next;
public TrieNode() {
isWord = false;
next = new HashMap<>();
}
public void add(String str) {
TrieNode node = this;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (!node.next.containsKey(c)) {
node.next.put(c, new TrieNode());
}
node = node.next.get(c);
}
node.isWord = true;
}
}
分析
提交结果
还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。
输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。
解答
public boolean makesquare(int[] nums) {
int len = nums.length;
int sum = 0;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int i = 0;i < len;i++){
sum += nums[i];
max = Math.max(max,nums[i]);
min = Math.min(min,nums[i]);
}
if(sum % 4 != 0)return false;
int edgeLen = sum / 4;
if(max > edgeLen || (max < edgeLen && max + min > edgeLen))return false;
int[] visited = new int[len];
return dfs(visited,nums,0,edgeLen,0);
}
public boolean dfs(int[] visited,int[] nums,int temp,int edgeLen,int step){
if(temp > edgeLen) return false;
if(step == 4 && temp == 0)return true;
for(int i = 0;i < nums.length;i++){
if(visited[i] == 0){
visited[i] = 1;
if(temp + nums[i] == edgeLen){
if(dfs(visited,nums,0,edgeLen,step + 1))
return true;
}else{
if(dfs(visited,nums,temp + nums[i],edgeLen,step))
return true;
}
visited[i] = 0;
}
}
return false;
}
分析
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
解答
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for(String str : strs){
int[] counts = getCounts(str);
for(int zeroNumber = m;zeroNumber >= 0;zeroNumber--){
for(int oneNumber = n;oneNumber >= 0;oneNumber--){
if(zeroNumber >= counts[0] && oneNumber >= counts[1])
dp[zeroNumber][oneNumber] = Math.max(dp[zeroNumber][oneNumber],dp[zeroNumber - counts[0]][oneNumber - counts[1]] + 1);
}
}
}
return dp[m][n];
}
public int[] getCounts(String str){
int[] res = new int[2];
for(int i = 0;i < str.length();i++){
if(str.charAt(i) == '0')res[0]++;
else res[1]++;
}
return res;
}
分析
这是背包问题,只不过这里有两个背包,分别装1和0
所以需要2维的dp数组,dp[i] [j] 表示i个0和j个1 最多可以拿多少个字符串
动态转移方程
dp[i] [j] = Math.max(dp[i] [j],dp[i - k[0]] [j - k[1]] + 1);
k[0] 表示当前字符串的0的个数,k[1]表示当前字符串1的个数。
按顺序遍历字符串,从大到小遍历i和j 就可得到结果
冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。
现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。
说明:所有供暖器都遵循你的半径标准,加热的半径也一样。
解答
//方法1
public int findRadius(int[] houses, int[] heaters) {
Arrays.sort(houses);
Arrays.sort(heaters);
int res = 0;
int i = 0;
for (int house : houses) {
for (i = 0; i < heaters.length - 1; i++) {
if (Math.abs(heaters[i] - house) < Math.abs(heaters[i + 1] - house)) {
break;
}
}
res = Math.max(res, Math.abs(heaters[i] - house));
}
return res;
}
//方法2
public int findRadius(int[] houses, int[] heaters) {
//二分查找需要对象有序
Arrays.sort(heaters);
int maxR = 0;
for(int house : houses){
//需所有房屋最小供暖器距离最大值
maxR = Math.max(maxR, search(house, heaters));
}
return maxR;
}
private int search(int house, int[] heaters) {
int left = 0, right = heaters.length - 1;
while (left <= right) {
//折半查找
int mid = left + (right - left) / 2;
//当前位置有供暖器那么这个距离就为 0
if(heaters[mid] == house){
return 0;
} else if(heaters[mid] > house){
right = mid - 1;
} else {
left = mid + 1;
}
}
//如果一直找最后发现 left 出了 heaters 右边界,说明当前房屋位置是大于最大供暖器位置的,直接相减
if(left > heaters.length - 1){
return house - heaters[heaters.length - 1];
}
//如果一直找最后发现 right 小于 0,说明当前房屋位置是小于最小供暖器位置的,直接相减
if(right < 0){
return heaters[0] - house;
}
//最后分别在该房屋两边各找到了最近的供暖器,那么取这两个供暖器到当前房屋最近距离即可
return Math.min(heaters[left] - house,house -heaters[right]);
}
分析
提交结果
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
解答
public int findComplement(int num) {
String str = Integer.toBinaryString(num);
int res = 0;
int n = 1;
for(int i = str.length() - 1;i >=0 ;i--){
char cur = str.charAt(i);
if(cur == '0'){
res += n;
}
n *= 2;
}
return res;
}
分析
两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。
计算一个数组中,任意两个数之间汉明距离的总和。
解答
public int totalHammingDistance(int[] nums) {
int len = nums.length;
int res = 0;
for(int i = 0;i <= 31;i++){
int t = 0;
for(int j = 0;j < len;j++){
int cur = nums[j] & (1 << i);
if(cur > 0)t++;
}
res += t * (len - t);
}
return res;
}
分析
给定圆的半径和圆心的 x、y 坐标,写一个在圆中产生均匀随机点的函数 randPoint 。
说明:
解答
class Solution {
double x_center;
double y_center;
double radius;
public Solution(double radius, double x_center, double y_center) {
this.x_center = x_center;
this.y_center = y_center;
this.radius = radius;
}
public double[] randPoint() {
double x_min = x_center - radius;
double x_max = x_center + radius;
double y_min = y_center - radius;
double y_max = y_center + radius;
while(true){
double x = Math.random() * (x_max - x_min) + x_min;
double y = Math.random() * (y_max - y_min) +y_min;
if(Math.pow(x - x_center,2) + Math.pow(y - y_center,2) < Math.pow(radius,2))
return new double[]{x,y};
}
}
}
分析
你需要找到由两个 n 位数的乘积组成的最大回文数。
由于结果会很大,你只需返回最大回文数 mod 1337得到的结果。
示例:
输入: 2
输出: 987
解释: 99 x 91 = 9009, 9009 % 1337 = 987
说明:
n 的取值范围为 [1,8]。
解答
public int largestPalindrome(int n) {
if (n == 1){
return 9;
}
String max = "";
String min = "1";
for (int i = 0; i < n; i++) {
max += "9";
}
for (int i = 0; i < n - 1; i++) {
min += "0";
}
long maxResultNum = Long.parseLong(max);
long minResultNum = Long.parseLong(min);
long indexNum = maxResultNum;
while (indexNum >= minResultNum) {
long thisResult = getHuiwen(indexNum);//构造回文数
long thisNum = maxResultNum;
while(thisNum > minResultNum && thisNum * thisNum > thisResult){//要使回文数最大,所以第一位为9,那么最后一位回文数就是9 所以 乘数一定是3、7、9结尾的
if(thisResult%thisNum==0)
return (int) (thisResult%1337);
if(thisNum%10==9){
thisNum-=2;
}else
thisNum-=4;
}
indexNum--;
}
return 0;
}
public long getHuiwen(long num) {
char[] numCharArray = String.valueOf(num).toCharArray();
int length = numCharArray.length;
StringBuilder result = new StringBuilder(num + "");
for (int i = length - 1; i >= 0; i--) {
result.append(numCharArray[i]);
}
return Long.parseLong(result.toString());
}
分析
最大回文数一定是9开头的
那么它的最后一位也必定是9
所以限定了乘数最后一位只能是3、7、9
才有可能得到最后一位是9的情况。
根据给定的n 得到乘数的最大值和最小值的范围。
从大到小遍历乘数
根据乘数 构造回文数。
若乘数相乘得到的结果大于构造出来的回文数。
若回文数可以整除乘数,说明找到了答案。返回结果
若乘数%10 ==9。则减2 用7去判断
否则减4 用3去判断