46. 全排列
47. 全排列 II
有条件的全排列,打印出[1,2,2,3,4,5]的所有4不在头并且3和5不挨着的所有排列
2 实现LRU
实现LRU
LinkedHashMap只保持输入顺序,在get时如果存在就删掉原来的数据,重新插入,这样该数据就会在map的最后,put时如果已经存在也将其删除再重新插入,因此最不常用的kv对保存在最前面,所以当容量满的时候要删掉最不常用的kv对就删除最前面的,这可以采用迭代器Iterator
来完成。
第二种方法就是继承LinkedHashMap
public class LRUCache extends LinkedHashMap {
private final int CACHE_SIZE;
/**
* 传递进来最多能缓存多少数据
*
* @param cacheSize 缓存大小
*/
public LRUCache(int cacheSize) {
// true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。
//0.75f为加载因子,扩展容量时,是用初始容量*加载因子
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
public int get(int key) {
if (!super.containsValue(key)){
return -1;
}
return super.get(key);
}
//重写removeEldestEntry()方法,afterNodeInsertion()方法会调用该方法的
//removeEldestEntry返回true,当插入新数据时会通过afterNodeInsertion()方法删除最老的数据
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
// 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
return size() > CACHE_SIZE;
}
}
LRU缓存机制还提了一种双向链表的方法。
3 字符串相乘
4 K 个一组翻转链表
牛客 每k个一组翻转链表
头插法
尾插法
直接举个例子: k = 3
pre
tail head
dummy 1 2 3 4 5
# 我们用tail 移到要翻转的部分最后一个元素
pre head tail
dummy 1 2 3 4 5
cur
# 我们尾插法的意思就是,依次把cur移到tail后面
pre tail head
dummy 2 3 1 4 5
cur
# 依次类推
pre tail head
dummy 3 2 1 4 5
cur
....
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode root = new ListNode(0);
root.next = head;
int len=0;
while(head!=null){
head=head.next;
len++;
}
head = root.next;
ListNode pre = root;
ListNode cur = head;
ListNode next;
for (int i = 0; i < len/k; i++) {
//这一段很巧妙
for (int j = 1; j < k; j++) {
next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
pre = cur;
cur = pre.next;
}
return root.next;
}
}
[图片上传失败...(image-ae8173-1571574629208)]
5 翻转链表
头插法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode newList=new ListNode(-1);//创建出来的单节点它的下一个节点是null
while(head!=null){
ListNode next=head.next;
head.next=newList.next;
newList.next=head;
head=next;
}
return newList.next;
}
}
6 翻转链表的部分
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode root = new ListNode(-1);
root.next = head;
ListNode pre = root;
for(int i=0;i
*7 删除链表中重复的节点
递归
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if (pHead == null || pHead.next == null)
return pHead;
ListNode next = pHead.next;
if (pHead.val == next.val) {
while (next != null && pHead.val == next.val)
next = next.next;
return deleteDuplication(next);
} else {
pHead.next = deleteDuplication(pHead.next);
return pHead;
}
}
}
非递归
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null || pHead.next==null)
return pHead;
ListNode temp_pre = null;
ListNode temp = pHead;
while(temp!=null && temp.next!=null){
if(temp.val==temp.next.val){
ListNode point = temp;
while(point.next!=null && point.val==point.next.val){
point = point.next;
}
temp = point.next;
if(temp_pre!=null) {
temp_pre.next = temp;
}
else{
pHead = temp;
}
continue;
}
temp_pre = temp;
temp = temp_pre.next;
}
return pHead;
}
}
*8 二叉树转成双链表,单链表
单链表
//类似于后序遍历,不太容易想到
class Solution {
TreeNode pre = null;
public void flatten(TreeNode root) {
if(root==null || (root.left==null&& root.right==null))
return;
m(root);
}
public void m(TreeNode root){
if(root==null)
return;
m(root.right);
m(root.left);
root.left = null;
root.right = pre;
pre = root;
}
}
//按规则办事
将左子树插入到右子树的地方
将原来的右子树接到左子树的最右边节点
考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null
可以看图理解下这个过程。
1
/
2 5
/ \
3 4 6
//将 1 的左子树插入到右子树的地方
1
2 5
/ \
3 4 6
//将原来的右子树接到左子树的最右边节点
1
2
/ \
3 4
5
6
//将 2 的左子树插入到右子树的地方
1
2
\
3 4
5
6
//将原来的右子树接到左子树的最右边节点
1
2
\
3
4
5
6
......
代码的话也很好写,首先我们需要找出左子树最右边的节点以便把右子树接过来。
链接
class Solution {
public void flatten(TreeNode root) {
if(root==null || (root.left==null&& root.right==null))
return;
TreeNode p = root;
while(p!=null){
//左子树为 null,直接考虑下一个节点
if(p.left!=null){
// 找左子树最右边的节点
TreeNode temp = p.left;
while(temp.right!=null){
temp = temp.right;
}
//将原来的右子树接到左子树的最右边节点
temp.right = p.right;
// 将左子树插入到右子树的地方
p.right = p.left;
p.left = null;
}
// 下一个节点
p = p.right;
}
}
}
二叉树转双向链表
109. 有序链表转换二叉搜索树
53. 最大子序和
class Solution {
public int maxSubArray(int[] nums) {
if(nums==null || nums.length==0)
return 0;
int max = nums[0];
int sum = 0;
for(int i=0;i
变型的有152. 乘积最大子序列
/**
求最大值,可以看成求被0拆分的各个子数组的最大值。
当一个数组中没有0存在,则分为两种情况:
1.负数为偶数个,则整个数组的各个值相乘为最大值;
2.负数为奇数个,则从左边开始,乘到最后一个负数停止有一个“最大值”,从右边也有一个“最大值”,比较,得出最大值。
*/
class Solution {
public int maxProduct(int[] nums) {
if(nums==null || nums.length==0){
return 0;
}
int a=1;
int max=nums[0];
for(int num:nums){
a=a*num;
if(max=0;i--){
a=a*nums[i];
if(max
2进制转10进制(晓磊华为面试)
java-------华为机试-----------进制转化
public class Main {
public static void main(String[] args) {
// System.out.println(Integer.MIN_VALUE);
String binNum = Integer.toBinaryString(-777);
int n = binNum.length();
int c = 0;
//负数
if (n == 32 && '1' == binNum.charAt(0)) {
StringBuilder sb = new StringBuilder(binNum);
//由于负数是补码,需要先减1, 把符号位也搞进去是为了处理Integer.MIN_VALUE
for (int i = n - 1; i >= 0; i--) {
if ('0' == sb.charAt(i)) {
sb.replace(i, i + 1, "1");
} else {
sb.replace(i, i + 1, "0");
break;
}
}
//取反 再算
for (int i = 0; i < n; i++) {
c = c * 2 + ('1' - sb.charAt(i));
}
c*=(-1);
}
//正数
else {
for (int i = 0; i < n; i++) {
c = c * 2 + (binNum.charAt(i) - '0');
}
}
System.out.println(c);
}
}
Java实现任意进制转换,没考虑负数,负数的情况还是相当复杂的
10进制小数转化为任意进制小数
java进制转换(无视正负数的差别)
221. 最大正方形(晓磊华为面试)
边长可动态规划,看其题解
public class Solution {
public int maximalSquare(char[][] matrix) {
int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0;
int[][] dp = new int[rows + 1][cols + 1];
int maxsqlen = 0;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
if (matrix[i-1][j-1] == '1'){
dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
maxsqlen = Math.max(maxsqlen, dp[i][j]);
}
}
}
return maxsqlen * maxsqlen;
}
}
695. 岛屿的最大面积
class Solution {
int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
public int maxAreaOfIsland(int[][] grid) {
if(grid==null || grid.length==0){
return 0;
}
int m = grid.length;
int n = grid[0].length;
int res = 0;
for(int i=0;i=0 && x=0 && y
200. 岛屿数量一个道理
class Solution {
int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
public int numIslands(char[][] grid) {
if(grid==null||grid.length==0)
return 0;
int m = grid.length;
int n = grid[0].length;
int res = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == '1') {
res++;
bfs(grid, i, j);
}
}
}
return res;
}
public void bfs(char[][] grid, int i,int j){
grid[i][j]='0';
for(int k=0;k<4;k++){
int x = dirs[k][0]+i;
int y = dirs[k][1]+j;
if(x>=0 && x=0 && y
和为S的连续正数序列
方法一:双指针
import java.util.ArrayList;
public class Solution {
public ArrayList > FindContinuousSequence(int sum) {
//存放结果
ArrayList > result = new ArrayList<>();
//两个起点,相当于动态窗口的两边,根据其窗口内的值的和来确定窗口的位置和大小
int plow = 1,phigh = 2;
while(phigh > plow){
//由于是连续的,差为1的一个序列,那么求和公式是(a0+an)*n/2
int cur = (phigh + plow) * (phigh - plow + 1) / 2;
//相等,那么就将窗口范围的所有数添加进结果集
if(cur == sum){
ArrayList list = new ArrayList<>();
for(int i=plow;i<=phigh;i++){
list.add(i);
}
result.add(list);
plow++;
//如果当前窗口内的值之和小于sum,那么右边窗口右移一下
}else if(cur < sum){
phigh++;
}else{
//如果当前窗口内的值之和大于sum,那么左边窗口右移一下
plow++;
}
}
return result;
}
}
方法二:链接
1)由于我们要找的是和为S的连续正数序列,因此这个序列是个公差为1的等差数列,而这个序列的中间值代表了平均值的大小。假设序列长度为n,那么这个序列的中间值可以通过(S / n)得到,知道序列的中间值和长度,也就不难求出这段序列了。
2)满足条件的n分两种情况:
n为奇数时,序列中间的数正好是序列的平均值,所以条件为:(n & 1) == 1 && sum % n == 0;
n为偶数时,序列中间两个数的平均值是序列的平均值,而这个平均值的小数部分为0.5,所以条件为:(sum % n) * 2 == n.
3)由题可知n >= 2,那么n的最大值是多少呢?我们完全可以将n从2到S全部遍历一次,但是大部分遍历是不必要的。为了让n尽可能大,我们让序列从1开始,
根据等差数列的求和公式:S = (1 + n) * n / 2,得到[图片上传失败...(image-b97db8-1571574629208)].
最后举一个例子,假设输入sum = 100,我们只需遍历n = 13~2的情况(按题意应从大到小遍历),n = 8时,得到序列[9, 10, 11, 12, 13, 14, 15, 16];n = 5时,得到序列[18, 19, 20, 21, 22]。
完整代码:时间复杂度为[图片上传失败...(image-447c99-1571574629208)])
import java.util.ArrayList;
public class Solution {
public ArrayList > FindContinuousSequence(int sum) {
ArrayList> ans = new ArrayList<>();
for (int n = (int) Math.sqrt(2 * sum); n >= 2; n--) {
if ((n & 1) == 1 && sum % n == 0 || (sum % n) * 2 == n) {
ArrayList list = new ArrayList<>();
for (int j = 0, k = (sum / n) - (n - 1) / 2; j < n; j++, k++) {
list.add(k);
}
ans.add(list);
}
}
return ans;
}
}
739. 每日温度(华为手撸)
动态规划
/**
* 根据题意,从最后一天推到第一天,这样会简单很多。因为最后一天显然不会再有升高的可能,结果直接为0。
* 再看倒数第二天的温度,如果比倒数第一天低,那么答案显然为1,如果比倒数第一天高,又因为倒数第一天
* 对应的结果为0,即表示之后不会再升高,所以倒数第二天的结果也应该为0。
* 自此我们容易观察出规律,要求出第i天对应的结果,只需要知道第i+1天对应的结果就可以:
* - 若T[i] < T[i+1],那么res[i]=1;
* - 若T[i] > T[i+1]
* - res[i+1]=0,那么res[i]=0;
* - res[i+1]!=0,那就比较T[i]和T[i+1+res[i+1]](即将第i天的温度与比第i+1天大的那天的温度进行比较)
*/
public int[] dailyTemperatures(int[] T) {
int[] res = new int[T.length];
res[T.length - 1] = 0;
for (int i = T.length - 2; i >= 0; i--) {
for (int j = i + 1; j < T.length; j += res[j]) {
if (T[i] < T[j]) {
res[i] = j - i;
break;
} else if (res[j] == 0) {
res[i] = 0;
break;
}
}
}
return res;
}
//和上面一样的思路,不同的写法
public int[] dailyTemperatures(int[] T) {
int[] res = new int[T.length];
if(T.length<2) return res;
res[T.length-1]=0;
for(int i=T.length-2;i>=0;i--){
if(T[i]=T[k]){
if(res[k]==0){
k=i;//这里这样赋值,是为了下面 rst[i] = k-i 为0
break;
}
k+=res[k];
}
res[i] = k-i;
}
}
return res;
}
单调栈,存的是索引
相对于上面的方法慢的非常多LinkedList
public int[] dailyTemperatures(int[] T) {
int[] res = new int[T.length];
// 单调栈 里面的数 非递增排序
Stack stack = new Stack();
// 从后往前遍历
for(int i = T.length-1; i >= 0; i--){
// 当前元素比栈顶元素大 出栈 重新调整栈直至满足要求
while(!stack.isEmpty() && T[i] >= T[stack.peek()]){
stack.pop();
}
// 栈为空 即后面没有比当前天温度高的
// 不为空 栈顶元素对应的下标减去当前下标即为经过几天后温度比当前天温度高
res[i] = stack.isEmpty()? 0 :stack.peek()-i;
// 当前元素进栈
stack.push(i);
}
return res;
}
单调栈的模板:
public int[] dailyTemperatures(int[] T) {
//...根据业务定义一些变量
//定义一个栈
Stack stack = new Stack();
// 遍历
for(int i = T.length-1; i >= 0; i--){
// 当前元素比栈顶元素大 出栈 重新调整栈直至满足要求
while(!stack.isEmpty() && T[i] >= T[stack.peek()]){
stack.pop();
}
//自己的业务逻辑
// 当前元素进栈,可以是索引也可以是值
stack.push(i);
}
return result;//返回结果
}
1019. 链表中的下一个更大节点
单调栈,LinkedList
public int[] nextLargerNodes(ListNode head) {
ListNode p = head;
ArrayList list = new ArrayList<>();
while(p!=null){
list.add(p.val);
p = p.next;
}
int[] res = new int[list.size()];
Stack stack = new Stack<>();
for(int i = list.size()-1;i>=0;i--){
while(!stack.isEmpty() && list.get(i)>=stack.peek()){
stack.pop();
}
res[i] = stack.isEmpty()? 0 : stack.peek();
stack.push(list.get(i));
}
return res;
}
则 dp 推进公式为:
- if nums[i + 1] > nums[i] then dp[i] = nums[i + 1]
- if nums[i + 1] == nums[i] then dp[i] = dp[i + 1]
- else dp[i] = { 遍历 dp[i + 1] ... dp[n],寻找最近大于 nums[i] 的值,遇到 0 停止遍历,遇到 0 表示后面没有更大的值了 }
public int[] nextLargerNodes(ListNode head) {
ListNode p = head;
ArrayList list = new ArrayList<>();
while(p!=null){
list.add(p.val);
p = p.next;
}
int[] res = new int[list.size()];
res[list.size()-1]=0;
for(int i = list.size()-2;i>=0;i--){
if(list.get(i)
1162. 地图分析(华为手撸)
暴力
class Solution {
public int maxDistance(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
ArrayList list = new ArrayList<>();
for(int i=0;i
bfs,链接
class Solution {
public int maxDistance(int[][] grid) {
int m = grid.length, n = grid[0].length;
Queue queue = new LinkedList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
queue.offer(new int[]{i, j});
}
}
}
if (queue.isEmpty() || queue.size() == m * n) return -1;
int[][] next = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
int level = -1;
while (!queue.isEmpty()) {
int count = queue.size();
for (int i = 0; i < count; i++) {
int[] cur = queue.poll();
for (int[] nt: next) {
int nx = cur[0] - nt[0], ny = cur[1] - nt[1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == 0) {
grid[nx][ny] = 1;
queue.offer(new int[]{nx, ny});
}
}
}
level++;
}
return level;
}
}
二分查找(递归,循环)(华为手撸)
java实现二分查找-两种方式
二叉树最大值,第k大值,https://www.nowcoder.com/discuss/249864?type=2&order=0&pos=14&page=2
72. 编辑距离
动态规划:
dp[i][j]
代表 word1 到 i 位置转换成 word2 到 j 位置需要最少步数
所以,
当word1[i] == word2[j],dp[i][j] = dp[i-1][j-1]
;
当 word1[i] != word2[j],dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1
dp[i-1][j-1]
到dp[i][j]
需要进行替换操作(删除+添加),dp[i-1][j]
到d[i][j]
需要进行删除操作,dp[i][j-1]
到d[i][j]
需要进行添加操作。
注意,针对第一行,第一列要单独考虑,我们引入 ''
下图所示:
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
if(m==0||n==0)
return m+n;
int[][] dp = new int[m+1][n+1];
for(int i=1;i<=m;i++){
dp[i][0]=dp[i-1][0]+1;
}
for(int i=1;i<=n;i++){
dp[0][i]=dp[0][i-1]+1;
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}
else{
dp[i][j] = Math.min(dp[i-1][j-1],Math.min(dp[i][j-1],dp[i-1][j]))+1;
}
}
}
return dp[m][n];
}
}
两个字符串,第一个去掉哪些字符后,它的子字符串能和另一个匹配。(华为手撸)
直接暴力
最长公共子序列
https://blog.csdn.net/qq_41693034/article/details/99861347
https://www.nowcoder.com/questionTerminal/c996bbb77dd447d681ec6907ccfb488a
分两种情况,直接输出最长公共子序列的长度以及子序列的详细内容
//只输出最长长度
public class LCS {
public int findLCS(String A, int n, String B, int m) {
int[][] dp = new int[n+1][m+1];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(A.charAt(i-1)==B.charAt(j-1)){
dp[i][j] = 1+dp[i-1][j-1];
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[n][m];
}
}
//输出一个子序列字符串
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static String process(String str1, String str2) {
if (str1 == null || str1.length() == 0 || str2 == null || str2.length() == 0) {
return "";
}
char[] char1 = str1.toCharArray();
int[][] dp = findLCS(str1, str1.length(), str2, str2.length());
for (int i = 0; i < dp.length; i++) {
System.out.println(Arrays.toString(dp[i]));
}
int m = str1.length();
int n = str2.length();
char[] res = new char[dp[m][n]];
int index = res.length - 1;
while (index >= 0) {
if (n > 0 && dp[m][n] == dp[m][n - 1]) {
n--;
} else if (m > 0 && dp[m][n] == dp[m - 1][n]) {
m--;
} else {
res[index--] = char1[m-1];
m--;
n--;
}
}
return String.valueOf(res);
}
public static int[][] findLCS(String A, int n, String B, int m) {
// write code here
int[][] dp = new int[n+1][m+1];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(A.charAt(i-1)==B.charAt(j-1)){
dp[i][j] = 1+dp[i-1][j-1];
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String str1 = scan.nextLine();
String str2 =scan.nextLine();
System.out.println(process(str1, str2));
}
}
原理就是先搞到动态规划的矩阵,如输入
1A2C3D4B56
B1D23CA45B6A
得到dp
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, ==1==, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]
[0, 0, 1, 1, ==2==, 2, 2, 2, 2, 2, 2, 2, 2]
[0, 0, 1, 1, 2, 2, ==3==, 3, 3, 3, 3, 3, 3]
[0, 0, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3]
[0, 0, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3]
[0, 0, 1, 2, 2, 3, 3, 3, ==4==, 4, 4, 4, 4]
[0, 1, 1, 2, 2, 3, 3, 3, 4, 4, ==5==, 5, 5]
[0, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5]
[0, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5, ==6==, 6]
然后从右下角往左上走,遇到最后一个不同于左上的数字所对应的索引位置的字符就是所求。
[图片上传失败...(image-511985-1571574629208)]
[图片上传失败...(image-c9478b-1571574629208)]
最长公共子串
public class LongestSubstring {
public int findLongest(String A, int n, String B, int m) {
int[][] dp = new int[n+1][m+1];
int max = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(A.charAt(i-1)==B.charAt(j-1)){
dp[i][j] = dp[i-1][j-1]+1;
max = Math.max(max,dp[i][j]);
}
}
}
return max;
}
}
输入
1AB2345CD
12345EF
得到dp
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, ==1==, 0, 0, 0, 0, 0]
[0, 0, 0, ==2==, 0, 0, 0, 0]
[0, 0, 0, 0, ==3==, 0, 0, 0]
[0, 0, 0, 0, 0, ==4==, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
198. 打家劫舍
dp 方程 dp[i] = max(dp[i-2]+nums[i], dp[i-1])\
class Solution {
public int rob(int[] nums) {
if(nums==null || nums.length==0)
return 0;
int n = nums.length;
int[] dp = new int[n+2];
for(int i=2;i
213. 打家劫舍 II(华为)
就是198题分成两种情况,第一个可取和第一个不可取,然后全两者的最大值
class Solution {
public int rob(int[] nums) {
if(nums==null || nums.length==0)
return 0;
int n = nums.length;
if(n==1){
return nums[0];
}
if(n==2){
return Math.max(nums[0],nums[1]);
}
int[] dp1 = new int[n+1];
//第一个可取
for(int i=2;i
337. 打家劫舍 III
class Solution {
public int rob(TreeNode root) {
int[] res = doRob(root);
return Math.max(res[0],res[1]);
}
//res[0]为不包括根节点的最大值,res[1]为包括根节点的最大值
private int[] doRob(TreeNode root){
int[] res = new int[2];
if(root == null)
return res;
int[] left = doRob(root.left);
int[] right = doRob(root.right);
//不包含根节点,最大值为两个子树的最大值之和
res[0] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
//包含根节点,最大值为两个子树不包含根节点的最大值加上根节点的值
res[1] = left[0] + right[0] + root.val;
return res;
}
}
662. 二叉树最大宽度(华为)
class Solution {
public int widthOfBinaryTree(TreeNode root) {
if(root==null)
return 0;
return m(root);
}
public int m(TreeNode root){
LinkedList queue = new LinkedList<>();
LinkedList q_index = new LinkedList<>();
queue.add(root);
q_index.add(1);
int max=1;
while(!queue.isEmpty()){
int size = queue.size();
while((size--)>0){
TreeNode temp = queue.poll();
int idx = q_index.poll();
if(temp.left!=null){
queue.add(temp.left);
q_index.add(2*idx);
}
if(temp.right!=null){
queue.add(temp.right);
q_index.add(2*idx+1);
}
}
if(q_index.size() >= 2) {
max = Math.max(max, q_index.getLast()-q_index.getFirst()+1);
}
}
return max;
}
}
作者:aaron_yu
链接:https://leetcode-cn.com/problems/maximum-width-of-binary-tree/solution/ceng-ci-bian-li-shi-xian-by-aaron_yu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
超时104/108
class Solution {
public int max = 0;
public int widthOfBinaryTree(TreeNode root) {
if(root==null)
return 0;
m(root);
return max;
}
public void m(TreeNode root){
LinkedList queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
ArrayList list = new ArrayList<>();
int size = queue.size();
boolean flag = true;
while((size--)>0){
TreeNode temp = queue.poll();
if(temp==null){
queue.add(null);
queue.add(null);
list.add(Integer.MIN_VALUE);
}else{
list.add(temp.val);
queue.add(temp.left);
queue.add(temp.right);
flag = false;
}
}
if(flag || list.size()<=max){
break;
}else{
int i = 0,j = list.size()-1;
while(i
153. 寻找旋转排序数组中的最小值
二分
class Solution {
public int findMin(int[] nums) {
if(nums==null||nums.length==0){
return 0;
}
int l=0,r = nums.length-1;
while(lnums[r]){
l = mid+1;
}else{
r = mid;
}
}
return nums[l];
}
}
二分递归
class Solution {
public int findMin(int[] nums) {
if(nums==null||nums.length==0){
return 0;
}
int n = nums.length;
return doFindMin(nums, 0, n-1);
}
public int doFindMin(int[] nums, int l, int r) {
if(l==r){
return nums[l];
}
int mid = (r-l)/2+l;
if(nums[mid]>nums[r]){
return doFindMin(nums, mid+1, r);
}else{
return doFindMin(nums, l, mid);
}
}
}
154. 寻找旋转排序数组中的最小值 II(华为)
方法和153一样,还是二分,就是多了一种情况nums[mid]==nums[r],r--就行
class Solution {
public int findMin(int[] nums) {
if(nums==null || nums.length==0){
return 0;
}
int l=0,r = nums.length-1;
while(lnums[r]){
l = mid+1;
}else if(nums[mid]==nums[r]){
r--;
}else{
r = mid;
}
}
return nums[l];
}
}
135. 分发糖果(华为)
这道题比较的方向不能搞错
正确解法:
class Solution {
public int candy(int[] ratings) {
int[] ca = new int[ratings.length];
ca[0]=1;
for(int i=1;iratings[i-1]){
ca[i] = ca[i-1]+1;
}
else{
ca[i]=1;
}
}
for(int i=ca.length-2;i>=0;i--){
if(ratings[i]>ratings[i+1]&&ca[i]<=ca[i+1]){
ca[i] = ca[i+1]+1;
}
}
int res = 0;
for(int i=0;i
错误解法,案例[1,2,3,2,1],比较的方向不对
public static int candy(int[] ratings) {
int[] ca = new int[ratings.length];
Arrays.fill(ca,1);
for(int i=0;iratings[i+1]&&ca[i]<=ca[i+1]){
ca[i] = ca[i+1]+1;
}
}
for(int i=ca.length-1;i>0;i--){
if(ratings[i]>ratings[i-1]&&ca[i]<=ca[i-1]){
ca[i] = ca[i-1]+1;
}
}
System.out.println(Arrays.toString(ca));
int res = 0;
for(int i=0;i
325. 和等于 k 的最长子数组长度
15. 三数之和
三数之和搞成两数之和,左右指针(注意去重)
class Solution {
public List> threeSum(int[] nums) {
Arrays.sort(nums);
List> ls = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) { // 跳过可能重复的答案
int l = i + 1, r = nums.length - 1, sum = 0 - nums[i];
while (l < r) {
if (nums[l] + nums[r] == sum) {
ls.add(Arrays.asList(nums[i], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
} else if (nums[l] + nums[r] < sum) {
while (l < r && nums[l] == nums[l + 1]) l++; // 跳过重复值
l++;
} else {
while (l < r && nums[r] == nums[r - 1]) r--;
r--;
}
}
}
}
return ls;
}
}
18. 四数之和(酷家乐)
在三数之和的基础上外加一层循环
class Solution {
public List> fourSum(int[] nums, int target) {
List> ls = new ArrayList<>();
if(nums==null || nums.length<4)
return ls;
Arrays.sort(nums);
for(int j=0;j0&&nums[j]==nums[j-1]) continue;
for (int i = j+1; i < nums.length - 2; i++) {
if (i > j+1 && nums[i] == nums[i - 1]) continue; // 跳过可能重复的答案
int l = i + 1, r = nums.length - 1, sum = target - nums[i]-nums[j];
while (l < r) {
if (nums[l] + nums[r] == sum) {
ls.add(Arrays.asList(nums[j],nums[i], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
} else if (nums[l] + nums[r] < sum) {
while (l < r && nums[l] == nums[l + 1]) l++; // 跳过重复值,其实可以不谢这个while,因为如果一样那下次还是会进入这个elseif
l++;
} else {
while (l < r && nums[r] == nums[r - 1]) r--;
r--;
}
}
}
}
return ls;
}
}
k数之和
==先对 nums 排序再调用==
public static ArrayList> kSum(int nums[],int target,int k, int start){
ArrayList> res = new ArrayList>();
if(start>=nums.length)
return res;
if(k==2){
int l = start, h = nums.length-1;
while(l list = new ArrayList<>();
list.add(nums[l]);
list.add(nums[h]);
res.add(list);
while(l2){
for(int i=start;i> temp = kSum(nums, target - nums[i], k - 1, i + 1);
if(temp!=null) {
for (List l : temp) {
l.add(0, nums[i]);
}
res.addAll(temp);
}
while(i
16. 最接近的三数之和
class Solution {
public int threeSumClosest(int[] nums, int target) {
// 排序
Arrays.sort(nums);
int closestNum = nums[0] + nums[1] + nums[2];
for (int i = 0; i < nums.length - 2; i++) {
int l = i + 1, r = nums.length - 1;
while (l < r){
int threeSum = nums[l] + nums[r] + nums[i];
if (Math.abs(threeSum - target) < Math.abs(closestNum - target)) {
closestNum = threeSum;
}
if (threeSum > target) {
r--;
} else if (threeSum < target) {
l++;
} else {
// 如果已经等于target的话, 肯定是最接近的
return target;
}
}
}
return closestNum;
}
}
328. 奇偶链表(华为)
插入法
class Solution {
public ListNode oddEvenList(ListNode head) {
if(head==null || head.next==null || head.next.next==null)
return head;
//已排好位置的奇数链表的最后一个节点
ListNode p = head;
//已排好位置的偶数链表的最后一个节点
ListNode c = p.next;
//第一个偶数位置,保持不动
ListNode q = c;
while(c!=null && c.next!=null){
ListNode t = c.next;
c.next = t.next;
p.next = t;
t.next = q;
p = p.next;
c = c.next;
}
return head;
}
}
奇偶两个链表
class Solution {
public ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
// head 为奇链表头结点,o 为奇链表尾节点
ListNode o = head;
// p 为偶链表头结点
ListNode p = head.next;
// e 为偶链表尾节点
ListNode e = p;
while (o.next != null && e.next != null) {
o.next = e.next;
o = o.next;
e.next = o.next;
e = e.next;
}
o.next = p;
return head;
}
}
869. 重新排序得到 2 的幂(华为)
//统计数字种类以及个数
class Solution {
public boolean reorderedPowerOf2(int N) {
int[] A = count(N);
for (int i = 0; i < 31; ++i)
if (Arrays.equals(A, count(1 << i)))
return true;
return false;
}
//统计数字的种类与个数是否相同
// Returns the count of digits of N
// Eg. N = 112223334, returns [0,2,3,3,1,0,0,0,0,0]
public int[] count(int N) {
int[] ans = new int[10];
while (N > 0) {
ans[N % 10]++;
N /= 10;
}
return ans;
}
}
//全排列,比较慢
class Solution {
public boolean reorderedPowerOf2(int N) {
char[] cs = String.valueOf(N).toCharArray();
return dfs(cs, 0);
}
public boolean dfs(char[] cs, int s){
if(s==cs.length-1){
if(cs[0]=='0')
return false;
int n = Integer.valueOf(new String(cs));
return isPowerOf2(n);
}
for(int i=s;i1){
// if((n&1)==1)
// return false;
// n/=2;
// }
// return true;
}
public void swap(char[] cs,int i,int j){
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}
227. 基本计算器 II(华为)
class Solution {
public int calculate(String s) {
//加个“+”是为了保证最后一个数能够被运算到
s = s.replace(" ","")+"+";
Stack stack = new Stack<>();
int d = 0;
// 保存上一个符号,初始为 +
char sign = '+';
for(char c : s.toCharArray()){
if(c>='0'&&c<='9'){
d = d*10+(int)(c-'0');
}else{
if(sign=='+'){
stack.push(d);
}else if(sign=='-'){
stack.push(-d);
}else if(sign=='*'){
stack.push(stack.pop()*d);
}else if(sign=='/'){
stack.push(stack.pop()/d);
}
sign = c;
d=0;
}
}
int res=0;
while(!stack.isEmpty()){
res += stack.pop();
}
return res;
}
}
224. 基本计算器
71. 简化路径(华为)
class Solution {
public String simplifyPath(String path) {
LinkedList queue = new LinkedList<>();
path = path.replace("//", "/");
String[] strs = path.split("/");
for (String s : strs) {
if ("..".equals(s)) {
if (!queue.isEmpty()) {
queue.pop();
}
} else if (".".equals(s)) {
continue;
} else if (!"".equals(s)) {
queue.push(s);
}
}
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
sb.append("/" + queue.pollLast());
}
return "".equals(sb.toString()) ? "/" : sb.toString();
}
}
5. 最长回文子串(华为)
class Solution {
public String longestPalindrome(String s) {
if(s==null || s.length()==0){
return "";
}
int n = s.length();
int max = 1;
int left = 0;
int[][] dp = new int[n][n];
for(int i=0;i
516. 最长回文子序列
class Solution {
public int longestPalindromeSubseq(String s) {
if(s==null || s.length()==0)
return 0;
int n = s.length();
int[][] dp = new int[n][n];
for(int i=0;i
图的算法
图的搜索算法:BFS和DFS详解(Java实现)
Dijkstra算法(三)之 Java详解
202. 快乐数
和为k的最长子数组
404. 左叶子之和
方法一
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root==null)
return 0;
return m(root);
}
public int m(TreeNode root) {
if (root == null)
return 0;
else if (root.left != null && root.left.left == null && root.left.right == null) {
return root.left.val + m(root.right);
}
return m(root.left) + m(root.right);
}
}
方法二:
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root==null)
return 0;
return m(root,root);
}
public int m(TreeNode parent,TreeNode root) {
int sum = 0;
if (root == null)
return 0;
else if (root.left == null && root.right == null) {
if(parent.left==root) {
sum += root.val;
}
return sum;
}
return sum + m(root,root.left) + m(root,root.right);
}
}
叶子节点之和
public class Main {
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int x) {
this.val = x;
}
}
public static int m( TreeNode root) {
int sum = 0;
if (root == null)
return 0;
else if (root.left == null && root.right == null) {
sum += root.val;
return sum;
}
return sum + m(root.left) + m(root.right);
}
public static void main(String[] args) {
TreeNode n1 = new TreeNode(3);
TreeNode n2 = new TreeNode(9);
TreeNode n3 = new TreeNode(20);
TreeNode n4 = new TreeNode(15);
TreeNode n5 = new TreeNode(7);
n1.left = n2;
n1.right = n3;
n3.left = n4;
n3.right = n5;
System.out.println(m(n1));
}
}
百钱买百鸡
公鸡5文钱一只,母鸡3文钱一只,小鸡3只一文钱,用100文钱买一百只鸡,其中公鸡,母鸡,小鸡都必须要有,问公鸡,母鸡,小鸡要买多少只刚好凑足100文钱。
多个循环的也可以,但是没有一个循环判断是否为整数的方法好
public class Main {
public static void main(String[] args) {
for (int x = 0; x <= 20; x++) {
double y = (200 - 14 * x) / 8.0;
// double z = 100 - x - y;
// if (y > 0 && z > 0 && Math.abs(y - (int) y) < 1e-5 && Math.abs(z - (int) z) < 1e-5)
if (y > 0 && Math.abs(y - (int) y) < 1e-5)
{
System.out.println(x + " " + ((int) y) + " " + (100-x-(int)y));
}
}
}
}
同样的思路的还有华为笔试题给定周长,求直角三角形的个数
x+y+z = n,x2+y2=z2,对x进行for循环,x2 = z2-y2=(z-y)(z+y)=(z-y)(n-x),从而得到
y=(n-x)/2-x2/(2(n-x));z = (n-x)/2+x2/(2(n-x))
其实y和z中只要一个是整数就行
public class Main {
public static void m(int n) {
for (int x = 1; x < n / 3; x++) {
double y = (n - x) / 2.0 - x * x / 2.0 / (n - x);
// double z = (n - x) / 2.0 + x * x / 2.0 / (n - x);
if (y > 0 && Math.abs(y - (int) y) < 1e-5 )
// if (y > 0 && z > 0 && Math.abs(y - (int) y) < 1e-5 && Math.abs(z - (int) z) < 1e-5)
{
System.out.println(x + " " + ((int) y) + " " + (n-x-(int)y));
}
}
}
public static void main(String[] args) {
m(120);
}
}
二叉树每个节点的值为0或者1,每个叶子节点所在路径都对应一个二进制数,将其转换为十进制,然后求所有十进制的和
public class Main {
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int x) {
this.val = x;
}
}
public static ArrayList res = new ArrayList<>();
public static void main(String[] args) {
TreeNode n1 = new TreeNode(1);
TreeNode n2 = new TreeNode(0);
TreeNode n3 = new TreeNode(1);
n1.left = n2;
n1.right = n3;
dfs(n1,new ArrayList());
System.out.println(res);
int sum = 0;
for (int i = 0; i < res.size(); i++) {
sum+=Long.parseLong(res.get(i),2);
}
System.out.println(sum);
}
public static void dfs(TreeNode root, ArrayList list) {
if (root == null) {
return;
}
list.add(""+root.val);
if(root.left==null && root.right==null){
res.add(String.join("", list));
}
if(root.left!=null){
dfs(root.left, list);
list.remove(list.size()-1);
}
if(root.right!=null){
dfs(root.right, list);
list.remove(list.size()-1);
}
}
}
257. 二叉树的所有路径
93. 复原IP地址
二进制中1的个数
要求效率最高
public class Solution {
public int NumberOf1(int n) {
int c = 0;
while(n!=0){
c++;
n = (n-1)&n;
}
return c;
}
}
public class Solution {
public int NumberOf1(int n) {
int c = 0;
while(n!=0){
c+=n&1;
//必须是>>>,无符号右移,如果采用>>,负数时会出现死循环
n = n>>>1;
}
return c;
}
}
19. 删除链表的倒数第N个节点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null)
return null;
ListNode p = head,q = head;
while((n--)>0){
p=p.next;
if(p==null)
return head.next;
}
while(p.next!=null){
p = p.next;
q = q.next;
}
q.next = q.next.next;
return head;
}
}
一个二维数组中查找一个字符串,方向是上下左右,每个位置只能用一次;
矩阵中的路径
回溯,有没有答案
public class Solution {
public static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public static int r, c;
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
r = rows;
c = cols;
int[] flag = new int[matrix.length];
for (int i = 0; i < matrix.length; i++) {
if (matrix[i] == str[0]) {
if (dfs(matrix, flag, i / cols, i % cols, str, 1)) {
return true;
}
}
}
return false;
}
public boolean dfs(char[] matrix, int[] flag, int i, int j, char[] str, int idx) {
if (idx == str.length) {
return true;
}
for (int k = 0; k < 4; k++) {
int x = i + dirs[k][0];
int y = j + dirs[k][1];
if (x >= 0 && x < r && y >= 0 && y < c
&& flag[x * c + y] == 0 && matrix[x * c + y] == str[idx]) {
flag[i * c + j] = 1;
if (dfs(matrix, flag, x, y, str, idx + 1)) {
return true;
}
flag[i * c + j] = 0;
}
}
return false;
}
}
279. 完全平方数
class Solution {
public int numSquares(int n) {
if(n<=3)
return n;
int[] dp = new int[n+1];
dp[1]=1;
dp[2]=2;
dp[3]=3;
for(int i=4;i<=n;i++){
int temp = Integer.MAX_VALUE;
for(int j=1;j*j<=i;j++){
temp=Math.min(temp,dp[i-j*j]+1);
}
dp[i] = temp;
}
return dp[n];
}
}
同样的思路
剪绳子
public class Solution {
public int cutRope(int target) {
//m>1
if(target==2)
return 1;
if(target==3)
return 2;
int[] dp = new int[1+target];
dp[1]=1;
dp[2]=2;
dp[3]=3;
for(int i=4;i<=target;i++){
int res = 0;
for(int j=1;j<=i/2;j++){
res = Math.max(res,dp[j]*dp[i-j]);
}
dp[i] = res;
}
return dp[target];
}
}
剪绳子方法二:链接
public class Solution {
public int cutRope(int target) {
//2 <= target <= 60
if(target==2)
return 1;
if(target==3)
return 2;
int[] dp = new int[1+target];
dp[1]=1;
dp[2]=2;
dp[3]=3;
for(int i=4;i<=target;i++){
int res = 0;
for(int j=1;j<=i/2;j++){
res = Math.max(res,dp[j]*dp[i-j]);
}
dp[i] = res;
}
return dp[target];
}
}
112. 路径总和
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root==null)
return false;
sum-=root.val;
if(root.left==null && root.right==null)
return sum==0;
return hasPathSum(root.left,sum)||hasPathSum(root.right,sum);
}
}
113. 路径总和 II
class Solution {
List> res = new ArrayList<>();
public List> pathSum(TreeNode root, int sum) {
dfs(root, sum, new ArrayList());
return res;
}
public void dfs(TreeNode root, int sum, ArrayList list){
if(root==null){
return;
}
list.add(root.val);
if(root.left==null && root.right==null && sum==root.val){
res.add(new ArrayList<>(list));
}
if(root.left!=null){
dfs(root.left,sum-root.val,list);
list.remove(list.size()-1);
}
if(root.right!=null){
dfs(root.right,sum-root.val,list);
list.remove(list.size()-1);
}
}
}