ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【Day11】每天三算法

2021-12-01 15:59:53  阅读:154  来源: 互联网

标签:每天 int res dp 算法 Day11 max array Math


【Day11】每天三算法

文章目录

题目

NC58 找到二叉搜索树中的两个交换节点(esay)

描述

一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请按升序输出这两个错误节点的值。(每个节点的值各不相同)

搜索二叉树:满足每个节点的左子节点小于当前节点,右子节点大于当前节点。

样例图

输入:{4,2,5,3,1}
返回值:[1,3]

思考

看到二叉搜索树,我们自然会想到其性质,即中序遍历后,节点的排列是有序的

那么对于题目中描述的情况,其中序遍历后的结果,就是一个两个元素被交换的有序数组(交换后其实不有序了)

那题目就变成了"找到有序数组中被交换位置的两个元素"

对于这个问题,其实是有固定解法的,大家可以自行悟一下:

建议在理解这段代码的时候,可以现在草稿纸上写几个有序数组被调换两个元素的示例

public static int[] getTwoSwap(int[]arr) {
  int[] res = new int[2];
  int first=-1;
  int second=-1;
  for (int i = 0; i < arr.length - 1; i++) {
    if (arr[i]>arr[i+1]) {
      if (first==-1) {
        first=i;
        second=i+1;
      } else {
        second=i+1;
      }
    }
  }
  res[0]=first;
  res[1]=second;
  return res;
}

剩下的,就是中序遍历了

题解

public class NC58_findError {
  	// 被调用的主函数
    public int[] findError (TreeNode root) {
        List<Integer> nums = new ArrayList<>();
        dfs(nums,root);
        return findErr(nums);
    }

    // 获取中序遍历的序列
    public void dfs(List<Integer>nums,TreeNode root) {
        if (root==null) return;
        dfs(nums,root.left);
        nums.add(root.val);
        dfs(nums,root.right);
    }

  	// 找到有序数组中被调换位置的两个元素
    public int[] findErr(List<Integer>nums) {
        int[] res = new int[2];
        int first = -1;
        int second = -1;
        for (int i = 0; i < nums.size()-1; i++) {
            if (nums.get(i)>nums.get(i+1)) {
                if (first==-1) {
                    first=i;
                    second=i+1;
                } else {
                    second=i+1;
                }
            }
        }
        res[0]=nums.get(second);
        res[1]=nums.get(first);
        return res;
    }

}

NC142 最长重复子串(medium)

描述

定义重复字符串是由两个相同的字符串首尾拼接而成,例如 abcabcabcab**c 便是长度为6的一个重复字符串,而 abcbaabcba 则不存在重复字符串。

给定一个字符串,请返回其最长重复子串的长度。

若不存在任何重复字符子串,则返回 0 。

本题中子串的定义是字符串中一段连续的区间。

示例:

输入:"ababc"
返回值:4
说明:abab为最长的重复字符子串,长度为4     
输入:"abcab"
返回值:0
说明:该字符串没有重复字符子串     

思考

方法一:暴力算法

外层循环是定义串的长度(1-n),当然,我们的长度可以从大到小进行枚举,这样只要答案出现就可以返回了,减少了判断次数

内层是定义串的起始位置,记录从当前起始位置最多能有几个重复的串

题解

public class NC142_solve {
    public static void main(String[] args) {
        NC142_solve solu = new NC142_solve();
        System.out.println(solu.solve("abcabcab"));
    }

    public int solve (String a) {
        if (a.length()<=1) return 0;
        // size不可能超过原串的一半
        // 字符串长度从大到小枚举,这样只要出现答案,我们直接返回即可
        for (int size = a.length()/2; size >=1 ; size--) {
            // 第二层循环,枚举的是起始位置
            for (int start = 0; start < a.length() - size; start++) {
                String currSub = a.substring(start, start+size);
                int l=start+size,r=l+size-1;
                int count=1; // count 至少要为2,才说明至少出现了一次重复
                while (r<a.length()) {
                    if (!currSub.equals(a.substring(l,r+1))) break;
                    count++;
                    l=r+1;
                    r=l+size-1;
                }
                //if (count>1) res=Math.max(res,count*size);
                if (count>1) return count*size;
            }
        }
        return 0;
    }
}

NC144 不相邻最大子序列和(medium)

描述

给你一个数组,其长度为 n ,在其中选出一个子序列,子序列中任意两个数不能有相邻的下标(子序列可以为空)

本题中子序列指在数组中任意挑选若干个数组成的数组。

思考

对于这道题,咱么的第一反应,就是动规,其子状态为:要么当前位置不选,和前一个位置保持一致,要么当前位置选,则 dp[k]=dp[k-2]+arr[k]

其状态转移方程可以写成如下形式:

dp[k] = max(dp[k-1],dp[k-1]+arr[k]) <当前位置选或不选哪个更大>

题解

public long subsequence (int n, int[] array) {
        if (array.length==1) return new Long(Math.max(0,array[0]));
        if (array.length==2) return new Long(Math.max(0,Math.max(array[0],array[1])));
        long[] dp = new long[n];
        dp[0]=array[0];
        dp[1]=array[1];
        long res = Math.max(0,Math.max(dp[0], dp[1]));
        for (int i = 2; i <n ; i++) {
            dp[i]=Math.max(dp[i-1],dp[i-2]+array[i]);
            res=Math.max(res,dp[i]);
        }
        return new Long(Math.max(0,res));
    }

在上述代码中,我们能够发现,每次只是使用了 dp 的前一个和前前一个元素,所以我们可以把 dp 数组优化没有

可以优化的部分

优化后的代码如下:

public long subsequence (int n, int[] array) {
        if (array.length==1) return new Long(Math.max(0,array[0]));
        if (array.length==2) return new Long(Math.max(0,Math.max(array[0],array[1])));
        long pre = array[0];
        long curr = array[1];
        long res = Math.max(0,Math.max(pre,curr));
        for (int i = 2; i <n ; i++) {
            long newPre = Math.max(curr, pre + array[i]);
            res=Math.max(res,newPre);
            pre=curr;
            curr=newPre;
        }
        return new Long(Math.max(0,res));
    }

标签:每天,int,res,dp,算法,Day11,max,array,Math
来源: https://blog.csdn.net/weixin_44062380/article/details/121657277

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有