class063 双向广搜【算法】

简介: class063 双向广搜【算法】

class063 双向广搜【算法】

算法讲解063【必备】双向广搜

code1 127. 单词接龙

// 单词接龙

// 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列

// 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> … -> sk :

// 每一对相邻的单词只差一个字母。

// 对于 1 <= i <= k 时,每个 si 都在 wordList 中

// 注意, beginWord 不需要在 wordList 中。sk == endWord

// 给你两个单词 beginWord 和 endWord 和一个字典 wordList

// 返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目

// 如果不存在这样的转换序列,返回 0 。

// 测试链接 : https://leetcode.cn/problems/word-ladder/

package class063;
import java.util.HashSet;
import java.util.List;
// 单词接龙
// 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列
// 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk :
// 每一对相邻的单词只差一个字母。
// 对于 1 <= i <= k 时,每个 si 都在 wordList 中
// 注意, beginWord 不需要在 wordList 中。sk == endWord
// 给你两个单词 beginWord 和 endWord 和一个字典 wordList
// 返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目
// 如果不存在这样的转换序列,返回 0 。
// 测试链接 : https://leetcode.cn/problems/word-ladder/
public class Code01_WordLadder {
  public static int ladderLength(String begin, String end, List<String> wordList) {
    // 总词表
    HashSet<String> dict = new HashSet<>(wordList);
    if (!dict.contains(end)) {
      return 0;
    }
    // 数量小的一侧
    HashSet<String> smallLevel = new HashSet<>();
    // 数量大的一侧
    HashSet<String> bigLevel = new HashSet<>();
    // 由数量小的一侧,所扩展出的下一层列表
    HashSet<String> nextLevel = new HashSet<>();
    smallLevel.add(begin);
    bigLevel.add(end);
    for (int len = 2; !smallLevel.isEmpty(); len++) {
      for (String w : smallLevel) {
        // 从小侧扩展
        char[] word = w.toCharArray();
        for (int j = 0; j < word.length; j++) {
          // 每一位字符都试
          char old = word[j];
          for (char change = 'a'; change <= 'z'; change++) {
            // // 每一位字符都从a到z换一遍
            if (change != old) {
              word[j] = change;
              String next = String.valueOf(word);
              if (bigLevel.contains(next)) {
                return len;
              }
              if (dict.contains(next)) {
                dict.remove(next);
                nextLevel.add(next);
              }
            }
          }
          word[j] = old;
        }
      }
      if (nextLevel.size() <= bigLevel.size()) {
        HashSet<String> tmp = smallLevel;
        smallLevel = nextLevel;
        nextLevel = tmp;
      } else {
        HashSet<String> tmp = smallLevel;
        smallLevel = bigLevel;
        bigLevel = nextLevel;
        nextLevel = tmp;
      }
      nextLevel.clear();
    }
    return 0;
  }
}

code2 牛牛的背包问题 P4799 [CEOI2015 Day2] 世界冰球锦标赛

// 牛牛的背包问题 & 世界冰球锦标赛

// 牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。

// 牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。

// 牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。

// 输入描述:

// 输入包括两行

// 第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量

// 第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积

// 输出描述:

// 输出一个正整数, 表示牛牛一共有多少种零食放法。

// 测试链接 : https://www.nowcoder.com/practice/d94bb2fa461d42bcb4c0f2b94f5d4281

// 测试链接 : https://www.luogu.com.cn/problem/P4799

// 请同学们务必参考如下代码中关于输入、输出的处理

// 这是输入输出处理效率很高的写法

// 提交以下所有代码,把主类名改成Main,可以直接通过

package class063;
// 牛牛的背包问题 & 世界冰球锦标赛
// 牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。
// 牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。
// 牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。
// 输入描述:
// 输入包括两行
// 第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量
// 第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积
// 输出描述:
// 输出一个正整数, 表示牛牛一共有多少种零食放法。
// 测试链接 : https://www.nowcoder.com/practice/d94bb2fa461d42bcb4c0f2b94f5d4281
// 测试链接 : https://www.luogu.com.cn/problem/P4799
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下所有代码,把主类名改成Main,可以直接通过
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Code02_SnacksWaysBuyTickets {
  public static int MAXN = 40;
  public static int MAXM = 1 << 20;
  public static long[] arr = new long[MAXN];
  public static long[] lsum = new long[MAXM];
  public static long[] rsum = new long[MAXM];
  public static int n;
  public static long w;
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StreamTokenizer in = new StreamTokenizer(br);
    PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    while (in.nextToken() != StreamTokenizer.TT_EOF) {
      n = (int) in.nval;
      in.nextToken();
      w = (long) in.nval;
      for (int i = 0; i < n; i++) {
        in.nextToken();
        arr[i] = (long) in.nval;
      }
      out.println(compute());
    }
    out.flush();
    out.close();
    br.close();
  }
  public static long compute() {
    int lsize = f(0, n >> 1, 0, w, lsum, 0);
    int rsize = f(n >> 1, n, 0, w, rsum, 0);
    Arrays.sort(lsum, 0, lsize);
    Arrays.sort(rsum, 0, rsize);
    long ans = 0;
    for (int i = lsize - 1, j = 0; i >= 0; i--) {
      while (j < rsize && lsum[i] + rsum[j] <= w) {
        j++;
      }
      ans += j;
    }
    return ans;
  }
  // arr[i....e]结束,e再往右不展开了!
  // 返回值 : ans数组填到了什么位置!
  public static int f(int i, int e, long s, long w, long[] ans, int j) {
    if (s > w) {
      return j;
    }
    // s <= w
    if (i == e) {
      ans[j++] = s;
    } else {
      // 不要arr[i]位置的数
      j = f(i + 1, e, s, w, ans, j);
      // 要arr[i]位置的数
      j = f(i + 1, e, s + arr[i], w, ans, j);
    }
    return j;
  }
}

code3 1755. 最接近目标值的子序列和

// 最接近目标值的子序列和

// 给你一个整数数组 nums 和一个目标值 goal

// 你需要从 nums 中选出一个子序列,使子序列元素总和最接近 goal

// 也就是说,如果子序列元素和为 sum ,你需要 最小化绝对差 abs(sum - goal)

// 返回 abs(sum - goal) 可能的 最小值

// 注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。

// 数据量描述:

// 1 <= nums.length <= 40

// -10^7 <= nums[i] <= 10^7

// -10^9 <= goal <= 10^9

// 测试链接 : https://leetcode.cn/problems/closest-subsequence-sum/

package class063;
import java.util.Arrays;
// 最接近目标值的子序列和
// 给你一个整数数组 nums 和一个目标值 goal
// 你需要从 nums 中选出一个子序列,使子序列元素总和最接近 goal
// 也就是说,如果子序列元素和为 sum ,你需要 最小化绝对差 abs(sum - goal)
// 返回 abs(sum - goal) 可能的 最小值
// 注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。
// 数据量描述:
// 1 <= nums.length <= 40
// -10^7 <= nums[i] <= 10^7
// -10^9 <= goal <= 10^9
// 测试链接 : https://leetcode.cn/problems/closest-subsequence-sum/
public class Code03_ClosestSubsequenceSum {
  public static int MAXN = 1 << 20;
  public static int[] lsum = new int[MAXN];
  public static int[] rsum = new int[MAXN];
  public static int fill;
  public static int minAbsDifference(int[] nums, int goal) {
    int n = nums.length;
    long min = 0;
    long max = 0;
    for (int i = 0; i < n; i++) {
      if (nums[i] >= 0) {
        max += nums[i];
      } else {
        min += nums[i];
      }
    }
    if (max < goal) {
      return (int) Math.abs(max - goal);
    }
    if (min > goal) {
      return (int) Math.abs(min - goal);
    }
    // 原始数组排序,为了后面递归的时候,还能剪枝
    // 常数优化
    Arrays.sort(nums);
    fill = 0;
    collect(nums, 0, n >> 1, 0, lsum);
    int lsize = fill;
    fill = 0;
    collect(nums, n >> 1, n, 0, rsum);
    int rsize = fill;
    Arrays.sort(lsum, 0, lsize);
    Arrays.sort(rsum, 0, rsize);
    int ans = Math.abs(goal);
    for (int i = 0, j = rsize - 1; i < lsize; i++) {
      while (j > 0 && Math.abs(goal - lsum[i] - rsum[j - 1]) <= Math.abs(goal - lsum[i] - rsum[j])) {
        j--;
      }
      ans = Math.min(ans, Math.abs(goal - lsum[i] - rsum[j]));
    }
    return ans;
  }
  public static void collect(int[] nums, int i, int e, int s, int[] sum) {
    if (i == e) {
      sum[fill++] = s;
    } else {
      // nums[i.....]这一组,相同的数字有几个
      int j = i + 1;
      while (j < e && nums[j] == nums[i]) {
        j++;
      }
      // nums[ 1 1 1 1 1 2....
      //       i         j
      for (int k = 0; k <= j - i; k++) {
        // k = 0个
        // k = 1个
        // k = 2个
        collect(nums, j, e, s + k * nums[i], sum);
      }
    }
  }
}

2023-12-9 12:55:23

相关文章
十进制与二进制、八进制、十六进制之间的互相转换,本文让你全部理清
十进制与二进制、八进制、十六进制之间的互相转换,本文让你全部理清
2671 0
十进制与二进制、八进制、十六进制之间的互相转换,本文让你全部理清
|
小程序 开发工具 开发者
解决微信开发者工具不能使用云开发的资源
解决微信开发者工具不能使用云开发的资源
|
机器学习/深度学习 vr&ar Python
|
机器学习/深度学习 人工智能 固态存储
深度学习在计算机视觉中的应用:重塑视觉感知的未来
【7月更文挑战第1天】深度学习重塑计算机视觉未来:本文探讨了深度学习如何革新CV领域,核心涉及CNN、RNN和自注意力机制。应用包括目标检测(YOLO、SSD等)、图像分类(VGG、ResNet等)、人脸识别及医学影像分析。未来趋势包括多模态融合、语义理解、强化学习和模型可解释性,推动CV向更高智能和可靠性发展。
|
缓存 分布式计算 监控
Spark 优化方案
Spark 优化方案
307 1
|
存储 搜索推荐 数据安全/隐私保护
分享5款小软件,看看能否成为你的小惊喜
生活中有时候需要一些小软件,它们或许并非必需,但却能为我们的日常增色不少。今天分享的5款非常规的小软件,看看它们是否能成为你生活中的小惊喜。
301 0
|
缓存 Java 数据库连接
java面试题目 强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
【6月更文挑战第28天】在 Java 中,理解和正确使用各种引用类型(强引用、软引用、弱引用、幻象引用)对有效的内存管理和垃圾回收至关重要。下面我们详细解读这些引用类型的区别及其具体使用场景。
359 3
|
XML JSON API
IOS网络编程:介绍一下 Alamofire 库。
IOS网络编程:介绍一下 Alamofire 库。
495 3
|
消息中间件 分布式计算 Kafka
硬核!Apache Hudi中自定义序列化和数据写入逻辑
硬核!Apache Hudi中自定义序列化和数据写入逻辑
419 1