Java 循环、递归、面向对象设计原则和模式、算法、多线程、SQL 优化、匹配算法
1:在 Java 语言中,for 循环适用于已知循环次数的情况,可以通过控制循环变量来实现循环。while 循环适用于未知循环次数的情况,可以通过条件判断来控制循环。递归适用于问题可以拆解为同样类型的子问题,并且每个子问题的解决方式与原问题相同的情况。
for 循环的优点是结构清晰,循环变量控制明确,适用于已知循环次数的情况。缺点是需要手动控制循环变量,容易出错。
while 循环的优点是适用于未知循环次数的情况,循环条件更为灵活。缺点是需要手动设置循环条件,容易出错。
递归的优点是可以将复杂问题拆解为简单问题,代码结构清晰。缺点是递归深度过大时会消耗大量的栈空间,可能导致栈溢出。
2:常用的面向对象设计原则有封装、继承、多态。
封装:将数据和方法封装在一个类中,通过访问修饰符控制对数据的访问,提高代码的安全性和可维护性。
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
继承:通过继承可以实现代码的复用,可以将公共的属性和方法提取到父类中。
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + ' is eating');
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
public void meow() {
System.out.println(name + ' is meowing');
}
}
多态:通过父类引用指向子类对象,实现对不同子类对象的统一操作。
public class Animal {
public void eat() {
System.out.println('Animal is eating');
}
}
public class Cat extends Animal {
public void eat() {
System.out.println('Cat is eating');
}
}
public class Dog extends Animal {
public void eat() {
System.out.println('Dog is eating');
}
}
public class Main {
public static void main(String[] args) {
Animal cat = new Cat();
Animal dog = new Dog();
cat.eat(); // 输出 'Cat is eating'
dog.eat(); // 输出 'Dog is eating'
}
}
3:常用的面向对象设计模式有策略模式、观察者模式、装饰者模式。
策略模式:定义一系列算法,将每个算法封装起来,并且使它们可以互换。
public interface Strategy {
void execute();
}
public class ConcreteStrategyA implements Strategy {
public void execute() {
System.out.println('Strategy A is executed');
}
}
public class ConcreteStrategyB implements Strategy {
public void execute() {
System.out.println('Strategy B is executed');
}
}
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
public class Main {
public static void main(String[] args) {
Context context = new Context();
Strategy strategyA = new ConcreteStrategyA();
context.setStrategy(strategyA);
context.executeStrategy(); // 输出 'Strategy A is executed'
Strategy strategyB = new ConcreteStrategyB();
context.setStrategy(strategyB);
context.executeStrategy(); // 输出 'Strategy B is executed'
}
}
观察者模式:定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。
public interface Observer {
void update();
}
public class ConcreteObserver implements Observer {
public void update() {
System.out.println('Observer is updated');
}
}
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer = new ConcreteObserver();
subject.attach(observer);
subject.notifyObservers(); // 输出 'Observer is updated'
subject.detach(observer);
subject.notifyObservers(); // 无输出
}
}
装饰者模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
public interface Component {
void operation();
}
public class ConcreteComponent implements Component {
public void operation() {
System.out.println('Component operation');
}
}
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
System.out.println('Decorator A operation');
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void operation() {
super.operation();
System.out.println('Decorator B operation');
}
}
public class Main {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation(); // 输出 'Component operation', 'Decorator A operation', 'Decorator B operation'
}
}
4:对于有 1000 个随机正整数的情况,可以使用贪心算法来实现分成两组,使得两组的总和尽量接近。
public class Main {
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4, 5, 6, 45, 67, ...}; // 1000 个随机正整数
Arrays.sort(nums); // 对数组进行排序
int sum1 = 0; // 第一组的总和
int sum2 = 0; // 第二组的总和
for (int i = nums.length - 1; i >= 0; i--) {
if (sum1 <= sum2) {
sum1 += nums[i];
} else {
sum2 += nums[i];
}
}
System.out.println('第一组的总和:' + sum1);
System.out.println('第二组的总和:' + sum2);
}
}
对于有 100000 个随机正整数的情况,可以使用动态规划算法来实现分成两组,使得两组的总和尽量接近。时间复杂度为 O(n^2),空间复杂度为 O(n)。
public class Main {
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4, 5, 6, 45, 67, ...}; // 100000 个随机正整数
int sum = 0; // 所有数的总和
for (int num : nums) {
sum += num;
}
int target = sum / 2; // 目标总和
boolean[][] dp = new boolean[nums.length + 1][target + 1];
dp[0][0] = true;
for (int i = 1; i <= nums.length; i++) {
for (int j = 0; j <= target; j++) {
dp[i][j] = dp[i - 1][j];
if (j >= nums[i - 1]) {
dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i - 1]];
}
}
}
int sum1 = 0; // 第一组的总和
int sum2 = 0; // 第二组的总和
for (int i = nums.length; i >= 1; i--) {
if (dp[i][target] && (sum1 <= sum2 || sum1 - nums[i - 1] > sum2)) {
sum1 += nums[i - 1];
} else {
sum2 += nums[i - 1];
}
}
System.out.println('第一组的总和:' + sum1);
System.out.println('第二组的总和:' + sum2);
}
}
6:在服务器 D 上使用 Java 的多线程来实现以上逻辑,可以使用线程池来管理多线程的执行。
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3); // 创建一个固定大小为 3 的线程池
Future<Integer> task1 = executorService.submit(new Task1());
Future<Integer> task2 = executorService.submit(new Task2());
Future<Integer> task3 = executorService.submit(new Task3());
int result = 0;
try {
result = task1.get() + task2.get() + task3.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println('任务 4 的结果:' + result);
executorService.shutdown(); // 关闭线程池
}
static class Task1 implements Callable<Integer> {
public Integer call() throws Exception {
// 任务 1 的逻辑
return 249;
}
}
static class Task2 implements Callable<Integer> {
public Integer call() throws Exception {
// 任务 2 的逻辑
return 354;
}
}
static class Task3 implements Callable<Integer> {
public Integer call() throws Exception {
// 任务 3 的逻辑
return 111;
}
}
}
7:该 SQL 能正确执行。
如果执行效率很差,可以通过以下优化来提高性能:
- 对表中的列建立索引,可以加快查询的速度。
- 优化 SQL 语句,避免使用子查询,使用连接查询或者其他更高效的方式实现相同的功能。
- 对表进行分区,可以分散数据并提高查询效率。
- 避免使用不必要的排序和聚合操作,只查询需要的列和行。
8:使用子查询方式实现该 SQL 可以改写为:
SELECT u.userid,
(SELECT SUM(m.value) FROM amount AS m WHERE m.orderid IN (SELECT t.orderid FROM trade AS t WHERE t.userid = u.userid AND DATE(t.trade_time) > DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND t.trade_type = 1)) AS sum_value,
(SELECT MAX(m.value) FROM amount AS m WHERE m.orderid IN (SELECT t.orderid FROM trade AS t WHERE t.userid = u.userid AND DATE(t.trade_time) > DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND t.trade_type = 1)) AS max_value,
(SELECT MIN(m.value) FROM amount AS m WHERE m.orderid IN (SELECT t.orderid FROM trade AS t WHERE t.userid = u.userid AND DATE(t.trade_time) > DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND t.trade_type = 1)) AS min_value,
(SELECT COUNT(t.id) FROM trade AS t WHERE t.userid = u.userid AND DATE(t.trade_time) > DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND t.trade_type = 1) / (SELECT COUNT(m.id) FROM amount AS m WHERE m.orderid IN (SELECT t.orderid FROM trade AS t WHERE t.userid = u.userid AND DATE(t.trade_time) > DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND t.trade_type = 1)) AS ratio
FROM user AS u
WHERE u.channel IN (SELECT channelid FROM channel_dict AS cd WHERE cd.channel_type = 1) OR u.ls_newbe = 1
GROUP BY u.userid
ORDER BY sum_value DESC;
9:使用 Java 语言实现投资人与借款人的匹配,可以使用贪心算法来实现。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
// 模拟投资人数据
List<Investor> investors = new ArrayList<>();
investors.add(new Investor(1, 1000));
investors.add(new Investor(2, 2000));
investors.add(new Investor(3, 3000));
// ...
// 模拟借款人数据
List<Borrower> borrowers = new ArrayList<>();
borrowers.add(new Borrower(1, 10000, 10));
borrowers.add(new Borrower(2, 20000, 12));
borrowers.add(new Borrower(3, 30000, 15));
// ...
// 对投资人按投资金额降序排序
Collections.sort(investors, Comparator.comparingInt(Investor::getAmount).reversed());
// 对借款人按借款金额升序排序
Collections.sort(borrowers, Comparator.comparingInt(Borrower::getAmount));
// 匹配投资人和借款人
int investorIndex = 0;
for (int i = 0; i < borrowers.size(); i++) {
Borrower borrower = borrowers.get(i);
while (investorIndex < investors.size()) {
Investor investor = investors.get(investorIndex);
if (investor.getAmount() >= borrower.getAmount()) {
// 找到匹配的投资人
investor.setAmount(investor.getAmount() - borrower.getAmount());
borrower.setAmount(0); // 设置借款人已借款
System.out.println('投资人 ' + investor.getId() + ' 匹配借款人 ' + borrower.getId());
investorIndex++;
break;
} else {
investorIndex++;
}
}
}
}
static class Investor {
private int id;
private int amount;
public Investor(int id, int amount) {
this.id = id;
this.amount = amount;
}
public int getId() {
return id;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
static class Borrower {
private int id;
private int amount;
private int interestRate;
public Borrower(int id, int amount, int interestRate) {
this.id = id;
this.amount = amount;
this.interestRate = interestRate;
}
public int getId() {
return id;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public int getInterestRate() {
return interestRate;
}
}
}
该代码首先模拟了投资人和借款人的数据,然后对投资人按投资金额降序排序,对借款人按借款金额升序排序。接下来,使用两个指针分别指向投资人和借款人列表的首部。每次从投资人列表中找到一个投资金额大于等于当前借款金额的投资人,进行匹配,并更新投资人剩余金额和借款人已借款金额。最后打印匹配结果。
该算法保证了每一笔借款都有对应的投资匹配,并且尽量保证收益最大化。因为该算法总是优先匹配投资金额最大的人,并且按照借款金额从小到大进行匹配,所以能够尽可能地将投资金额分配给利率更高的借款人,从而最大化收益。
该算法的时间复杂度为 O(nlogn),因为需要对投资人和借款人列表进行排序。空间复杂度为 O(1),因为只使用了一些常量大小的变量。
该算法是一个贪心算法,因为它每次都选择当前最优的匹配,并不保证全局最优解。但对于该问题来说,该算法的效率和效果都比较不错。
原文地址: https://www.cveoy.top/t/topic/pAq4 著作权归作者所有。请勿转载和采集!