918打卡

发布时间 2023-09-18 17:40:37作者: forever_fate

1. 两数之和(1)

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

思想:哈希表

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; ++i) {
            if (map.containsKey(target - nums[i])) {
                return new int[]{map.get(target - nums[i]), i};
            }
            map.put(nums[i], i);
        }
        return new int[0];
    }
}

2. 有序列表转换二叉搜索树 (109)

给定一个单链表的头节点  head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。

思想:分值,left,mid,right指针

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
   ListNode globalHead;

    public TreeNode sortedListToBST(ListNode head) {
        globalHead =head;
        int length = getLength(head);
        return buildTee(0,length-1);

    }

    private TreeNode buildTee(int left , int right) {
        if (left>right){
            return null;
        }

        int mid =  (left+right)/2;
        TreeNode root = new TreeNode();
        root.left = buildTee(left,mid-1);
        root.val = globalHead.val;
        globalHead = globalHead.next;
        root.right = buildTee(mid+1,right);
        return root;

    }

    private int getLength(ListNode head) {
        int ret = 0;
        while(head!=null){
            ret++;
            head =head.next;
        }
        return  ret;
    }
}

 3. 扰乱字符串 (87)

使用下面描述的算法可以扰乱字符串 s 得到字符串 t :

  1. 如果字符串的长度为 1 ,算法停止
  2. 如果字符串的长度 > 1 ,执行下述步骤:
    • 在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 x 和 y ,且满足 s = x + y 。
    • 随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x 。
    • 在 x 和 y 这两个子字符串上继续从步骤 1 开始递归执行此算法。

给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false 。

思想:动态规划

显然「扰乱字符串」的关系是具有对称性的,即如果 s1是 s2的扰乱字符串,那么 s2是 s1的扰乱字符串。为了叙述方便,我们称这种情况下,s1和 s2是「和谐」的。

如果 s1=s2,那么它们是「和谐」的;如果 s1和 s2的长度不同,那么它们一定不是「和谐」的;如果 s1中某个字符 c出现了 x1次,而 c在 s2中出现了 x2次,且 x1≠x2,那么它们一定不是「和谐」的。

class Solution {
 
    int [][][] memo;
    String s1,s2;

    public boolean isScramble(String s1, String s2) {
        int length = s1.length();
        this.memo = new int[length][length][length+1];
        this.s1=s1;
        this.s2=s2;
        return dfs(0,0,length); //一开始如果不和谐,则不会进行子串比较
    }

    private boolean dfs(int i1, int i2, int length) {
        if (memo[i1][i2][length] != 0){
            return memo[i1][i2][length]==1; //如果是0 表明还么开始比较
        }
        // 判断两个子串是否相等
        if (s1.substring(i1,i1+length) .equals(s2.substring(i2,i2+length))){
            memo[i1][i2][length]=1;
            return true;
        }
        // 判断是否存在字符 c 在两个子串中出现的次数不同
        if(!checkSame(i1,i2,length)){
            memo[i1][i2][length]=-1;
            return false;
        }
        //因为两字符串长度是相同的
        // 枚举分割位置,i是切分长度
        for (int i = 1; i <length ; i++) {
            //不交换的情况, i1,i2是两个字符串的切分起始点
            if (dfs(i1,i2,i) && dfs(i1+i,i2+i,length-i)){
                memo[i1][i2][length]=1;
                return true;
            }
            //交换
            if (dfs(i1,i2+length-i,i) && dfs(i1+i,i2,length-i)){
                memo[i1][i2][length]=1;
                return true;
            }
        }
        memo[i1][i2][length]=-1;
        return false;

    }

    private boolean checkSame(int i1, int i2, int length) {
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        for (int i = i1; i <i1+length ; i++) {
            char c = s1.charAt(i);
            map.put(c,map.getOrDefault(c,0)+1);
        }
        for (int i = i2; i <i2+length ; i++) {
            char c = s2.charAt(i);
            map.put(c,map.getOrDefault(c,0)-1);
        }
        for (Map.Entry<Character, Integer> entry : map.entrySet()) {
            int value = entry.getValue();
            if (value!=0){
                return false;
            }
        }
        return true;

    }

}

4. 位1 的个数 (191)

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量

思想: 位操作

class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
         int num = 0;
        while (n!=0){
            num+= n&1; //只比较最后一位  011111& 00001 = 000001   011110& 00001 = 000000
            n=n>>>1; //无符号右移一位
        }
        return num; 
    }
}

5.  分裂二叉树的最大乘积

给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。

由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回。

思想: 深度遍历

 

   int  avg, half;// avg:整棵树总值的中间值 half:真正的中间值
    public int maxProduct(TreeNode root) {
        int total = getTotal(root); // 获取这棵树总值
        avg = total/2;
        half=total;
        //优化half 使它不断接近整棵树一半的值
        getTotal(root);
        return (int)((long)half*(total-half)%(1e9+7));

    }

    private int getTotal(TreeNode root) {

        if (root==null){
            return  0;
        }
        int val = root.val+getTotal(root.left)+getTotal(root.right);
        //遍历到当前节点 对比其它节点 更接近中间值,把节点当作树
        if (Math.abs(val-avg)<Math.abs(half-avg)){
            half =val;
        }
        return val;
    }