给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-109 <= nums1[i], nums2[j] <= 109
思路:
有点像归并排序,可以利用双指针,无需开辟新空间,在nums1的最后进行合并。空间就优化为了O(1);
时间复杂度:O(n+m);
class Solution {
public:
void merge(vector& nums1, int m, vector& nums2, int n) {
int i = m-1,j=n-1,k=m+n-1;
while(i>=0&&j>=0){
if(nums1[i] <= nums2[j]){
nums1[k--] = nums2[j--];
}else{
nums1[k--] = nums1[i--];
}
}
while(i<0 && j>=0){
nums1[k--] = nums2[j--];
}
while(i>=0 && j<0){
nums1[k--] = nums1[i--];
}
};
};
Java学习:
多态
多态:多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。如下,一个实际类型为Student,引用类型为Person的变量,调用其run()方法,那么调用的实际上是student的run; Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。
public class Main {
public static void main(String[] args) {
Person p = new Student();
p.run();
}
}
class Person {
public void run() {
System.out.println("Person.run");
}
}
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
多态可不止于此,还有更加便利的地方。
在这个一个代码中,多态可以帮助我们实现通过person P这个参数跳转到不同的方法当中去。因为它可能是一个子类。
public void runTwice(Person p) { p.run(); p.run(); }
incomes有多个子类,在主函数中将income数组中赋值有income,salary,StateCouncilSpecialAllowance。虽然它们在开始时被定义为了父类,但是后面赋值成了子类,所以在调用total+=...的时候会跳转到相应的子类的方法当中去执行。
public class Main {
public static void main(String[] args) {
// 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}
public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
class Income {
protected double income;
public Income(double income) {
this.income = income;
}
public double getTax() {
return income * 0.1; // 税率10%
}
}
class Salary extends Income {
public Salary(double income) {
super(income);
}
@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
假如我们要新增一个税收项目,在以前的c语言当中挺难搞的。要改很多东西,比如重新开数组,结构体。 而在java当中如果我们要新增一种稿费收入,只需要从Income派生,然后正确覆写getTax()方法就可以。把新的类型传入totalTax(),不需要修改任何代码。
可见,多态具有一个非常强大的功能,就是允许添加更多类型的子类实现功能扩展,却不需要修改基于父类的代码。
假如我们想在子类的覆写方法中,调用父类的被覆写的方法:使用super
class Person {
protected String name;
public String hello() {
return "Hello, " + name;
}
}
Student extends Person {
@Override
public String hello() {
// 调用父类的hello()方法:
return super.hello() + "!";
}
}
final继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override:同样的也可以对类使用,表明了当前类不可被继承。对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。
抽象类:
如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法。抽象类不可被实例化,如果想要被实例化则必须把类本身也声明为abstract
abstract class Person {
public abstract void run();
}
无法实例化的抽象类有什么用?
因为抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
面向抽象编程当我们定义了抽象类Person,以及具体的Student、Teacher子类的时候,我们可以通过抽象类Person类型去引用具体的子类的实例。
这种引用抽象类的好处在于,我们对其进行方法调用,并不关心父类型变量的具体子类型。



