diff --git a/.gitignore b/.gitignore index fc6093b..1247fbd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -.idea/ -temp/ -en/empty-template-en.md -zh/empty-template-zh.md -/.ruby-version +/.idea +/temp +/tmp +.DS_Store diff --git a/README.md b/README.md index 2bdbeec..8ab19ce 100644 --- a/README.md +++ b/README.md @@ -1,156 +1,2776 @@ +# Learn-Rails-by-Reading-Source-Code +[![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE) +[![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) +## Table of Contents + + * [Part 0: Before reading Rails 5 source code](#part-0-before-reading-rails-5-source-code) + * [What will you learn from this tutorial?](#what-will-you-learn-from-this-tutorial) + * [Part 1: Your app: an instance of YourProject::Application](#part-1-your-app-an-instance-of-yourprojectapplication) + * [Part 2: config](#part-2-config) + * [Part 3: Every request and response](#part-3-every-request-and-response) + * [Puma](#puma) + * [Rack apps](#rack-apps) + * [The core app: ActionDispatch::Routing::RouteSet instance](#the-core-app-actiondispatchroutingrouteset-instance) + * [Render view](#render-view) + * [How can instance variables defined in Controller be accessed in view file?](#how-can-instance-variables-defined-in-controller-be-accessed-in-view-file) + * [Part 4: What does `$ rails server` do?](#part-4-what-does--rails-server-do) + * [Thor](#thor) + * [Rails::Server#start](#railsserverstart) + * [Starting Puma](#starting-puma) + * [Conclusion](#conclusion) + * [Exiting Puma](#exiting-puma) + * [Process and Thread](#process-and-thread) + * [Send `SIGTERM` to Puma](#send-sigterm-to-puma) + + +## Part 0: Before reading Rails 5 source code +1) I suggest you to learn Rack [http://rack.github.io/](http://rack.github.io/) first. + +In Rack, an object with `call` method is a Rack app. + +So what is the object with `call` method in Rails? I will answer this question in Part 1. + +2) You need a good IDE which can help for debugging. I use [RubyMine](https://www.jetbrains.com/). + +### What will you learn from this tutorial? +* How does Rails start your application? + +* How does Rails process every request? + +* How does Rails combine ActionController, ActionView and Routes together? + +* How does Puma, Rack, Rails work together? + +* What's Puma's multiple threads? + +I should start with the command `$ rails server`, but I put this to Part 4. Because it's a little bit complex. + +## Part 1: Your app: an instance of YourProject::Application +Assume your Rails app's class name is `YourProject::Application` (defined in `./config/application.rb`). + +First, I will give you a piece of important code. +```ruby +# ./gems/railties-5.2.2/lib/rails/commands/server/server_command.rb +module Rails + module Command + class ServerCommand < Base + def perform + # ... + Rails::Server.new(server_options).tap do |server| + # APP_PATH is '/path/to/your_project/config/application'. + # require APP_PATH will create the 'Rails.application' object. + # Actually, 'Rails.application' is an instance of `YourProject::Application`. + # Rack server will start 'Rails.application'. + require APP_PATH + + Dir.chdir(Rails.application.root) + + server.start + end + end + end + end + + class Server < ::Rack::Server + def start + #... + # 'wrapped_app' will get an well prepared app from `./config.ru` file. + # 'wrapped_app' will return an instance of `YourProject::Application`. + # But the instance of `YourProject::Application` returned is not created in 'wrapped_app'. + # It has been created when `require APP_PATH` in previous code: + # in Rails::Command::ServerCommand#perform + wrapped_app + + super # Will invoke ::Rack::Server#start. + end + end +end +``` +A Rack server need to start with an `App` object. The `App` object should have a `call` method. + +`config.ru` is the conventional entry file for Rack app. So let's look at it. +```ruby +# ./config.ru +require_relative 'config/environment' + +run Rails.application # It seems that this is the app. +``` + +Let's test it by `Rails.application.respond_to?(:call)`, it returns `true`. + +Let's step into `Rails.application`. + +```ruby +# ./gems/railties-5.2.2/lib/rails.rb +module Rails + class << self + @application = @app_class = nil + + attr_accessor :app_class + + # Oh, 'application' is a class method for module 'Rails'. It is not an object. + # But it returns an object which is an instance of 'app_class'. + # So it is important for us to know what class 'app_class' is. + def application + @application ||= (app_class.instance if app_class) + end + end +end +``` + +Because `Rails.application.respond_to?(:call)` returns `true`, `app_class.instance` has a `call` method. + +When was `app_class` set? +```ruby +module Rails + class Application < Engine + class << self + def inherited(base) # This is a hooked method. + Rails.app_class = base # This line set the 'app_class'. + end + end + end +end +``` + +`Rails::Application` is inherited by `YourProject`, +```ruby +# ./config/application.rb +module YourProject + # The hooked method `inherited` will be invoked here. + class Application < Rails::Application + end +end +``` +So `YourProject::Application` is the `Rails.app_class` here. + +You may have a question: When does Rails execute the code in `./config/application.rb`? + +To answer this question, we need to look back to `config.ru`. +```ruby +# ./config.ru +require_relative 'config/environment' # Let's step into this line. + +run Rails.application # It seems that this is the app. +``` + +```ruby +# ./config/environment.rb +# Load the Rails application. +require_relative 'application' # Let's step into this line. + +# Initialize the Rails application. +Rails.application.initialize! +``` + +```ruby +# ./config/application.rb +require_relative 'boot' + +require 'rails/all' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module YourProject + # The hooked method `inherited` will be invoked here. + class Application < Rails::Application + config.load_defaults 5.2 + config.i18n.default_locale = :zh + end +end +``` +Because `YourProject::Application` is `Rails.app_class`, `app_class.instance` is `YourProject::Application.instance`. + +But where is the `call` method? + +`call` method should be a method of `YourProject::Application.instance`. + +The `call` method processes every request. Here it is. +```ruby +# ./gems/railties/lib/rails/engine.rb +module Rails + class Engine < Railtie + def call(env) # This method will process every request. It is invoked by Rack. So it is very important. + req = build_request env + app.call req.env # We will discuss the 'app' object later. + end + end +end + +# ./gems/railties/lib/rails/application.rb +module Rails + class Application < Engine + end +end + +# ./config/application.rb +module YourProject + class Application < Rails::Application + end +end +``` + +Ancestor's chain is `YourProject::Application < Rails::Application < Rails::Engine < Rails::Railtie`. + +So `YourProject::Application.new.respond_to?(:call)` returns `true`. + +But what does `app_class.instance` really do? + +`instance` is just a method name. What we really expects is something like `app_class.new`. + +Let's look at the definition of `instance`. +```ruby +# ./gems/railties/lib/rails/application.rb +module Rails + class Application < Engine + def instance + super.run_load_hooks! # This line confused me at the beginning. + end + end +end +``` +After a deep research, I realized that this code is equal to: +```ruby +def instance + return_value = super # Keyword 'super' means call the ancestor's same name method: 'instance'. + return_value.run_load_hooks! +end +``` + +```ruby +# ./gems/railties/lib/rails/railtie.rb +module Rails + class Railtie + def instance + # 'Rails::Railtie' is the top ancestor class. + # Now 'app_class.instance' is 'YourProject::Application.new'. + @instance ||= new + end + end +end +``` + +```ruby +module Rails + def application + @application ||= (app_class.instance if app_class) + end +end +``` + +So `YourProject::Application.new` is `Rails.application`. + +Rack server will start `Rails.application` in the end. + +`Rails.application` is an important object in Rails. + +And you'll only have one `Rails.application` in one Puma process. + +Multiple threads in a Puma process shares the `Rails.application`. + +## Part 2: config +The first time we see the `config` is in `./config/application.rb`. +```ruby +# ./config/application.rb +#... +module YourProject + class Application < Rails::Application + # Actually, `config` is a method of `YourProject::Application`. + # It is defined in it's grandfather's father: `Rails::Railtie` + config.load_defaults 5.2 # Let's step into this line to see what is config. + config.i18n.default_locale = :zh + end +end +``` + +```ruby +module Rails + class Railtie + class << self + # Method `:config` is defined here. + # Actually, method `:config` is delegated to another object `:instance`. + delegate :config, to: :instance + + # Call `YourProject::Application.config` will actually call `YourProject::Application.instance.config` + def instance + # return an instance of `YourProject::Application`. + # Call `YourProject::Application.config` will actually call `YourProject::Application.new.config` + @instance ||= new + end + end + end + + class Engine < Railtie + end + + class Application < Engine + class << self + def instance + # 'super' will call `:instance` method in `Railtie`, + # which will return an instance of `YourProject::Application`. + return_value = super + return_value.run_load_hooks! + end + end + + def run_load_hooks! + return self if @ran_load_hooks + @ran_load_hooks = true + + # ... + self # `self` is an instance of `YourProject::Application`, and `self` is `Rails.application`. + end + + # This is the method `config`. + def config + # It is an instance of class `Rails::Application::Configuration`. + # Please notice that `Rails::Application` is superclass of `YourProject::Application` (self's class). + @config ||= Application::Configuration.new(self.class.find_root(self.class.called_from)) + end + end +end +``` +In the end, `YourProject::Application.config === Rails.application.config` returns `true`. + +Invoke Class's `config` method become invoke the class's instance's `config` method. + +```ruby +module Rails + class << self + def configuration + application.config + end + end +end +``` +So `Rails.configuration === Rails.application.config` returns `true`. + +FYI: +```ruby +module Rails + class Application + class Configuration < ::Rails::Engine::Configuration + end + end + + class Engine + class Configuration < ::Rails::Railtie::Configuration + attr_accessor :middleware + + def initialize(root = nil) + super() + #... + @middleware = Rails::Configuration::MiddlewareStackProxy.new + end + end + end + + class Railtie + class Configuration + end + end +end +``` + +## Part 3: Every request and response +Imagine we have this route for the home page. +```ruby +# ./config/routes.rb +Rails.application.routes.draw do + root 'home#index' # HomeController#index +end +``` + +### Puma +When a request is made from client, Puma will process the request in `Puma::Server#process_client`. + +If you want to know how Puma enter the method `Puma::Server#process_client`, please read part 4 or just search 'process_client' in this document. + +```ruby +# ./gems/puma-3.12.0/lib/puma/server.rb +require 'socket' + +module Puma + # The HTTP Server itself. Serves out a single Rack app. + # + # This class is used by the `Puma::Single` and `Puma::Cluster` classes + # to generate one or more `Puma::Server` instances capable of handling requests. + # Each Puma process will contain one `Puma::Server` instacne. + # + # The `Puma::Server` instance pulls requests from the socket, adds them to a + # `Puma::Reactor` where they get eventually passed to a `Puma::ThreadPool`. + # + # Each `Puma::Server` will have one reactor and one thread pool. + class Server + def initialize(app, events=Events.stdio, options={}) + # app: # + # @config = # + # > + @app = app + #... + end + + # Given a connection on +client+, handle the incoming requests. + # + # This method support HTTP Keep-Alive so it may, depending on if the client + # indicates that it supports keep alive, wait for another request before + # returning. + # + def process_client(client, buffer) + begin + # ... + while true + # Let's step into this line. + case handle_request(client, buffer) # Will return true in this example. + when true + return unless @queue_requests + buffer.reset + + ThreadPool.clean_thread_locals if clean_thread_locals + + unless client.reset(@status == :run) + close_socket = false + client.set_timeout @persistent_timeout + @reactor.add client + return + end + end + end + # ... + ensure + buffer.reset + client.close if close_socket + #... + end + end + + # Given the request +env+ from +client+ and a partial request body + # in +body+, finish reading the body if there is one and invoke + # the Rack app. Then construct the response and write it back to + # +client+ + # + def handle_request(req, lines) + env = req.env + # ... + # app: # + # @config = # + # > + status, headers, res_body = @app.call(env) # Let's step into this line. + + # ... + return keep_alive + end + end +end +``` +```ruby +# ./gems/puma-3.12.0/lib/puma/configuration.rb +module Puma + class Configuration + class ConfigMiddleware + def initialize(config, app) + @config = config + @app = app + end + + def call(env) + env[Const::PUMA_CONFIG] = @config + # @app: # + @app.call(env) + end + end + end +end +``` + +### Rack apps +As we see when Ruby enter `Puma::Configuration::ConfigMiddleware#call`, the `@app` is `YourProject::Application` instance. + +It is just the `Rails.application`. + +Rack need a `call` method to process request. + +Rails defined this `call` method in `Rails::Engine#call`, so that `YourProject::Application` instance will have a `call` method. + +```ruby +# ./gems/railties/lib/rails/engine.rb +module Rails + class Engine < Railtie + def call(env) # This method will process every request. It is invoked by Rack. + req = build_request env + app.call req.env # The 'app' method is blow. + end + + def app + # FYI, + # caller: [ + # "../gems/railties-5.2.2/lib/rails/application/finisher.rb:47:in `block in '", + # "../gems/railties-5.2.2/lib/rails/initializable.rb:32:in `instance_exec'", + # "../gems/railties-5.2.2/lib/rails/initializable.rb:32:in `run'", + # "../gems/railties-5.2.2/lib/rails/initializable.rb:63:in `block in run_initializers'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:347:in `each'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:347:in `call'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each'", + # "../ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each'", + # "../gems/railties-5.2.2/lib/rails/initializable.rb:61:in `run_initializers'", + # "../gems/railties-5.2.2/lib/rails/application.rb:361:in `initialize!'", + # "/Users/lanezhang/projects/mine/free-erp/config/environment.rb:5:in `'", + # "config.ru:2:in `require_relative'", "config.ru:2:in `block in
'", + # "../gems/rack-2.0.6/lib/rack/builder.rb:55:in `instance_eval'", + # "../gems/rack-2.0.6/lib/rack/builder.rb:55:in `initialize'", + # "config.ru:in `new'", "config.ru:in `
'", + # "../gems/rack-2.0.6/lib/rack/builder.rb:49:in `eval'", + # "../gems/rack-2.0.6/lib/rack/builder.rb:49:in `new_from_string'", + # "../gems/rack-2.0.6/lib/rack/builder.rb:40:in `parse_file'", + # "../gems/rack-2.0.6/lib/rack/server.rb:320:in `build_app_and_options_from_config'", + # "../gems/rack-2.0.6/lib/rack/server.rb:219:in `app'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:27:in `app'", + # "../gems/rack-2.0.6/lib/rack/server.rb:357:in `wrapped_app'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:92:in `log_to_stdout'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:54:in `start'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:149:in `block in perform'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:144:in `tap'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:144:in `perform'", + # "../gems/thor-0.20.3/lib/thor/command.rb:27:in `run'", + # "../gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'", + # "../gems/thor-0.20.3/lib/thor.rb:391:in `dispatch'", + # "../gems/railties-5.2.2/lib/rails/command/base.rb:65:in `perform'", + # "../gems/railties-5.2.2/lib/rails/command.rb:46:in `invoke'", + # "../gems/railties-5.2.2/lib/rails/commands.rb:18:in `'", + # "../path/to/your_project/bin/rails:5:in `require'", + # "../path/to/your_project/bin/rails:5:in `
'" + # ] + puts "caller: #{caller.inspect}" + + # You may want to know when is the @app first time initialized. + # It is initialized when 'config.ru' is load by Rack server. + # Please search `Rack::Server#build_app_and_options_from_config` in this document for more information. + # When `Rails.application.initialize!` (in ./config/environment.rb) executed, @app is initialized. + @app || @app_build_lock.synchronize { # '@app_build_lock = Mutex.new', so multiple threads share one '@app'. + @app ||= begin + # In the end, config.middleware will be an instance of ActionDispatch::MiddlewareStack with preset instance variable @middlewares (which is an Array). + stack = default_middleware_stack # Let's step into this line + # 'middleware' is a 'middleware_stack'! + config.middleware = build_middleware.merge_into(stack) + # FYI, this line is the last line and the result of this line is the return value for @app. + config.middleware.build(endpoint) # look at this endpoint below. We will enter method `build` later. + end + } + +# @app: # +# > +# ... +# > +# +# > +# > + @app + end + + # Defaults to an ActionDispatch::Routing::RouteSet instance. + def endpoint + ActionDispatch::Routing::RouteSet.new_with_config(config) + end + end +end +``` + +```ruby +# ./gems/railties/lib/rails/application... +module Rails + class Application < Engine + def default_middleware_stack + default_stack = DefaultMiddlewareStack.new(self, config, paths) + default_stack.build_stack # Let's step into this line. + end + + class DefaultMiddlewareStack + attr_reader :config, :paths, :app + + def initialize(app, config, paths) + @app = app + @config = config + @paths = paths + end + + def build_stack + ActionDispatch::MiddlewareStack.new do |middleware| + if config.force_ssl + middleware.use ::ActionDispatch::SSL, config.ssl_options + end + + middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header + + if config.public_file_server.enabled + headers = config.public_file_server.headers || {} + + middleware.use ::ActionDispatch::Static, paths["public"].first, index: config.public_file_server.index_name, headers: headers + end + + if rack_cache = load_rack_cache + require "action_dispatch/http/rack_cache" + middleware.use ::Rack::Cache, rack_cache + end + + if config.allow_concurrency == false + # User has explicitly opted out of concurrent request + # handling: presumably their code is not threadsafe + + middleware.use ::Rack::Lock + end + + middleware.use ::ActionDispatch::Executor, app.executor + + middleware.use ::Rack::Runtime + middleware.use ::Rack::MethodOverride unless config.api_only + middleware.use ::ActionDispatch::RequestId + middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies + + middleware.use ::Rails::Rack::Logger, config.log_tags + middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app + middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format + + unless config.cache_classes + middleware.use ::ActionDispatch::Reloader, app.reloader + end + + middleware.use ::ActionDispatch::Callbacks + middleware.use ::ActionDispatch::Cookies unless config.api_only + + if !config.api_only && config.session_store + if config.force_ssl && config.ssl_options.fetch(:secure_cookies, true) && !config.session_options.key?(:secure) + config.session_options[:secure] = true + end + middleware.use config.session_store, config.session_options + middleware.use ::ActionDispatch::Flash + end + + unless config.api_only + middleware.use ::ActionDispatch::ContentSecurityPolicy::Middleware + end + + middleware.use ::Rack::Head + middleware.use ::Rack::ConditionalGet + middleware.use ::Rack::ETag, "no-cache" + + middleware.use ::Rack::TempfileReaper unless config.api_only + end + end + end + end +end +``` +```ruby +# ./gems/actionpack-5.2.2/lib/action_dispatch/middleware/stack.rb +module ActionDispatch + class MiddlewareStack + def use(klass, *args, &block) + middlewares.push(build_middleware(klass, args, block)) + end + + def build_middleware(klass, args, block) + Middleware.new(klass, args, block) + end + + def build(app = Proc.new) + # See Enumerable#inject for more information. + return_val = middlewares.freeze.reverse.inject(app) do |a, middleware| + # a: app, and will be changed when iterating + # middleware: #, 'middleware' will be switched to another instance of ActionDispatch::MiddlewareStack::Middleware when iterating + middleware.build(a) # Let's step into this line. + end + + return_val + end + + class Middleware + def initialize(klass, args, block) + @klass = klass + @args = args + @block = block + end + + def build(app) + # klass is Rack middleware like : Rack::TempfileReaper, Rack::ETag, Rack::ConditionalGet or Rack::Head, etc. + # It's typical Rack app to use these middlewares. + # See https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib for more information. + klass.new(app, *args, &block) + end + end + end +end +``` +### The core app: ActionDispatch::Routing::RouteSet instance +```ruby +# Paste again FYI. +# @app: # +# > +# ... +# > +# +# > +# > +``` +As we see in the Rack middleware stack, the last @app is + +`@app=#` +```ruby +# ./gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb +module ActionDispatch + module Routing + class RouteSet + def initialize(config = DEFAULT_CONFIG) + @set = Journey::Routes.new + @router = Journey::Router.new(@set) + end + + def call(env) + req = make_request(env) # return ActionDispatch::Request.new(env) + req.path_info = Journey::Router::Utils.normalize_path(req.path_info) + @router.serve(req) # Let's step into this line. + end + end + end + +# ./gems/actionpack5.2.2/lib/action_dispatch/journey/router.rb + module Journey + class Router + class RoutingError < ::StandardError + end + + attr_accessor :routes + + def initialize(routes) + @routes = routes + end + + def serve(req) + find_routes(req).each do |match, parameters, route| # Let's step into 'find_routes' + set_params = req.path_parameters + path_info = req.path_info + script_name = req.script_name + + unless route.path.anchored + req.script_name = (script_name.to_s + match.to_s).chomp("/") + req.path_info = match.post_match + req.path_info = "/" + req.path_info unless req.path_info.start_with? "/" + end + + parameters = route.defaults.merge parameters.transform_values { |val| + val.dup.force_encoding(::Encoding::UTF_8) + } + + req.path_parameters = set_params.merge parameters + + # 'route' is an instance of ActionDispatch::Journey::Route. + # 'route.app' is an instance of ActionDispatch::Routing::RouteSet::Dispatcher. + status, headers, body = route.app.serve(req) # Let's step into method 'serve' + + if "pass" == headers["X-Cascade"] + req.script_name = script_name + req.path_info = path_info + req.path_parameters = set_params + next + end + + return [status, headers, body] + end + + [404, { "X-Cascade" => "pass" }, ["Not Found"]] + end + + def find_routes(req) + routes = filter_routes(req.path_info).concat custom_routes.find_all { |r| + r.path.match(req.path_info) + } + + routes = + if req.head? + match_head_routes(routes, req) + else + match_routes(routes, req) + end + + routes.sort_by!(&:precedence) + + routes.map! { |r| + match_data = r.path.match(req.path_info) + path_parameters = {} + match_data.names.zip(match_data.captures) { |name, val| + path_parameters[name.to_sym] = Utils.unescape_uri(val) if val + } + [match_data, path_parameters, r] + } + end + + end + end +end + +# ./gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb +module ActionDispatch + module Routing + class RouteSet + class Dispatcher < Routing::Endpoint + def serve(req) + params = req.path_parameters # params: { action: 'index', controller: 'home' } + controller = controller(req) # controller: HomeController + # The definition of 'make_response!' is + # ActionDispatch::Response.create.tap { |res| res.request = request; } + res = controller.make_response!(req) + dispatch(controller, params[:action], req, res) # Let's step into this line. + rescue ActionController::RoutingError + if @raise_on_name_error + raise + else + return [404, { "X-Cascade" => "pass" }, []] + end + end + + private + + def controller(req) + req.controller_class + rescue NameError => e + raise ActionController::RoutingError, e.message, e.backtrace + end + + def dispatch(controller, action, req, res) + controller.dispatch(action, req, res) # Let's step into this line. + end + end + end + end +end + +# ./gems/actionpack-5.2.2/lib/action_controller/metal.rb +module ActionController + class Metal < AbstractController::Base + abstract! + + def self.controller_name + @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore + end + + def self.make_response!(request) + ActionDispatch::Response.new.tap do |res| + res.request = request + end + end + + class_attribute :middleware_stack, default: ActionController::MiddlewareStack.new + + def self.inherited(base) + base.middleware_stack = middleware_stack.dup + super + end + + # Direct dispatch to the controller. Instantiates the controller, then + # executes the action named +name+. + def self.dispatch(name, req, res) + if middleware_stack.any? + middleware_stack.build(name) { |env| new.dispatch(name, req, res) }.call req.env + else + # 'self' is HomeController, so for this line Rails will new a HomeController instance. + # Invoke `HomeController.ancestors`, you can find many superclasses of HomeController. + # These are some typical superclasses of HomeController. + # HomeController + # < ApplicationController + # < ActionController::Base + # < ActiveRecord::Railties::ControllerRuntime (module included) + # < ActionController::Instrumentation (module included) + # < ActionController::Rescue (module included) + # < AbstractController::Callbacks (module included) + # < ActionController::ImplicitRender (module included) + # < ActionController::BasicImplicitRender (module included) + # < ActionController::Renderers (module included) + # < ActionController::Rendering (module included) + # < ActionView::Layouts (module included) + # < ActionView::Rendering (module included) + # < ActionDispatch::Routing::UrlFor (module included) + # < AbstractController::Rendering (module included) + # < ActionController::Metal + # < AbstractController::Base + new.dispatch(name, req, res) # Let's step into this line. + end + end + + def dispatch(name, request, response) + set_request!(request) + set_response!(response) + process(name) # Let's step into this line. + request.commit_flash + to_a + end + + def to_a + response.to_a + end + end +end + +# .gems/actionpack-5.2.2/lib/abstract_controller/base.rb +module AbstractController + class Base + def process(action, *args) + @_action_name = action.to_s + + unless action_name = _find_action_name(@_action_name) + raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}" + end + + @_response_body = nil + + # action_name: 'index' + process_action(action_name, *args) # Let's step into this line. + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/instrumentation.rb +module ActionController + module Instrumentation + def process_action(*args) + raw_payload = { + controller: self.class.name, + action: action_name, + params: request.filtered_parameters, + headers: request.headers, + format: request.format.ref, + method: request.request_method, + path: request.fullpath + } + + ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup) + + ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload| + begin + # self: # + result = super # Let's step into this line. + payload[:status] = response.status + result + ensure + append_info_to_payload(payload) + end + end + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/rescue.rb +module ActionController + module Rescue + def process_action(*args) + super # Let's step into this line. + rescue Exception => exception + request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions? + rescue_with_handler(exception) || raise + end + end +end + +# .gems/actionpack-5.2.2/lib/abstract_controller/callbacks.rb +module AbstractController + # = Abstract Controller Callbacks + # + # Abstract Controller provides hooks during the life cycle of a controller action. + # Callbacks allow you to trigger logic during this cycle. Available callbacks are: + # + # * after_action + # * before_action + # * skip_before_action + # * ... + module Callbacks + def process_action(*args) + run_callbacks(:process_action) do + # self: # + super # Let's step into this line. + end + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/rendering.rb +module ActionController + module Rendering + def process_action(*) + self.formats = request.formats.map(&:ref).compact + super # Let's step into this line. + end + end +end + +# .gems/actionpack-5.2.2/lib/abstract_controller/base.rb +module AbstractController + class Base + def process_action(method_name, *args) + # self: #, method_name: 'index' + # In the end, method 'send_action' is method 'send' by `alias send_action send` + send_action(method_name, *args) + end + + alias send_action send + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/basic_implicit_render.rb +module ActionController + module BasicImplicitRender + def send_action(method, *args) + # self: #, method_name: 'index' + # Because 'send_action' is an alias of 'send', + # self.send('index', *args) will goto HomeController#index. + x = super + # performed?: false (for this example) + x.tap { default_render unless performed? } # Let's step into 'default_render' later. + end + end +end + +# ./your_project/app/controllers/home_controller.rb +class HomeController < ApplicationController + # Will go back to BasicImplicitRender#send_action when method 'index' is done. + def index + # Question: How does the instance variable '@users' defined in HomeController can be accessed in './app/views/home/index.html.erb' ? + # I will answer this question later. + @users = User.all.pluck(:id, :name) + end +end +``` + +```html +# ./app/views/home/index.html.erb +
+

+ <%= t('home.banner_title') %> + <%= @users %> +

+
+``` + +### Render view +As we see in `ActionController::BasicImplicitRender::send_action`, the last line is `default_render`. + +So after `HomeController#index` is done, Ruby will execute method `default_render`. + +```ruby +# .gems/actionpack-5.2.2/lib/action_controller/metal/implicit_render.rb +module ActionController + # Handles implicit rendering for a controller action that does not + # explicitly respond with +render+, +respond_to+, +redirect+, or +head+. + module ImplicitRender + def default_render(*args) + # Let's step into template_exists? + if template_exists?(action_name.to_s, _prefixes, variants: request.variant) + # Rails has found the default template './app/views/home/index.html.erb', so render it. + render(*args) # Let's step into this line later + #... + else + logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger + super + end + end + end +end + +# .gems/actionview-5.2.2/lib/action_view/lookup_context.rb +module ActionView + class LookupContext + module ViewPaths + # Rails checks whether the default template exists. + def exists?(name, prefixes = [], partial = false, keys = [], **options) + @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options)) + end + alias :template_exists? :exists? + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/instrumentation.rb +module ActionController + module Instrumentation + def render(*args) + render_output = nil + self.view_runtime = cleanup_view_runtime do + Benchmark.ms { + # self: # + render_output = super # Let's step into super + } + end + render_output + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/rendering.rb +module ActionController + module Rendering + # Check for double render errors and set the content_type after rendering. + def render(*args) + raise ::AbstractController::DoubleRenderError if response_body + super # Let's step into super + end + end +end + +# .gems/actionpack-5.2.2/lib/abstract_controller/rendering.rb +module AbstractController + module Rendering + # Normalizes arguments, options and then delegates render_to_body and + # sticks the result in self.response_body. + def render(*args, &block) + options = _normalize_render(*args, &block) + + rendered_body = render_to_body(options) # Let's step into this line. + + if options[:html] + _set_html_content_type + else + _set_rendered_content_type rendered_format + end + + self.response_body = rendered_body + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/renderers.rb +module ActionController + module Renderers + def render_to_body(options) + _render_to_body_with_renderer(options) || super # Let's step into this line and 'super' later. + end + + # For this example, this method return nil in the end. + def _render_to_body_with_renderer(options) + # The '_renderers' is defined at line 31: `class_attribute :_renderers, default: Set.new.freeze.` + # '_renderers' is an instance predicate method. For more information, + # see ./gems/activesupport/lib/active_support/core_ext/class/attribute.rb + _renderers.each do |name| + if options.key?(name) + _process_options(options) + method_name = Renderers._render_with_renderer_method_name(name) + return send(method_name, options.delete(name), options) + end + end + nil + end + end +end + +# .gems/actionpack-5.2.2/lib/action_controller/metal/renderers.rb +module ActionController + module Rendering + def render_to_body(options = {}) + super || _render_in_priorities(options) || " " # Let's step into 'super' + end + end +end +``` + +```ruby +# .gems/actionview-5.2.2/lib/action_view/rendering.rb +module ActionView + module Rendering + def render_to_body(options = {}) + _process_options(options) + + _render_template(options) # Let's step into this line. + end + + def _render_template(options) + variant = options.delete(:variant) + assigns = options.delete(:assigns) + + context = view_context # We will step into this line later. + + context.assign assigns if assigns + lookup_context.rendered_format = nil if options[:formats] + lookup_context.variants = variant if variant + + view_renderer.render(context, options) # Let's step into this line. + end + end +end + +# .gems/actionview-5.2.2/lib/action_view/renderer/renderer.rb +module ActionView + class Renderer + def render(context, options) + if options.key?(:partial) + render_partial(context, options) + else + render_template(context, options) # Let's step into this line. + end + end + + # Direct access to template rendering. + def render_template(context, options) + TemplateRenderer.new(@lookup_context).render(context, options) # Let's step into this line. + end + end +end + +# .gems/actionview-5.2.2/lib/action_view/renderer/template_renderer.rb +module ActionView + class TemplateRenderer < AbstractRenderer + def render(context, options) + @view = context + @details = extract_details(options) + template = determine_template(options) + + prepend_formats(template.formats) + + @lookup_context.rendered_format ||= (template.formats.first || formats.first) + + render_template(template, options[:layout], options[:locals]) # Let's step into this line. + end + + def render_template(template, layout_name = nil, locals = nil) + view, locals = @view, locals || {} + + render_with_layout(layout_name, locals) do |layout| # Let's step into this line + instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do + # template: # + template.render(view, locals) { |*name| view._layout_for(*name) } # Let's step into this line + end + end + end + + def render_with_layout(path, locals) + layout = path && find_layout(path, locals.keys, [formats.first]) + content = yield(layout) + + if layout + view = @view + view.view_flow.set(:layout, content) + layout.render(view, locals) { |*name| view._layout_for(*name) } + else + content + end + end + end +end + +# .gems/actionview-5.2.2/lib/action_view/template.rb +module ActionView + class Template + def render(view, locals, buffer = nil, &block) + instrument_render_template do + # self: # + compile!(view) + # method_name: "_app_views_home_index_html_erb___3699380246341444633_70336654511160" (This method is defined in 'def compile(mod)' below) + # view: #<#:0x00007ff10ea050a8>, view is an instance of which has same instance variables defined in the instance of HomeController. + # You will get the result html after invoking 'view.send'. + view.send(method_name, locals, buffer, &block) + end + rescue => e + handle_render_error(view, e) + end + + # Compile a template. This method ensures a template is compiled + # just once and removes the source after it is compiled. + def compile!(view) + return if @compiled + + # Templates can be used concurrently in threaded environments + # so compilation and any instance variable modification must + # be synchronized + @compile_mutex.synchronize do + # Any thread holding this lock will be compiling the template needed + # by the threads waiting. So re-check the @compiled flag to avoid + # re-compilation + return if @compiled + + if view.is_a?(ActionView::CompiledTemplates) + mod = ActionView::CompiledTemplates + else + mod = view.singleton_class + end + + instrument("!compile_template") do + compile(mod) # Let's step into this line. + end + + # Just discard the source if we have a virtual path. This + # means we can get the template back. + @source = nil if @virtual_path + @compiled = true + end + end + + def compile(mod) + encode! + # @handler: # + code = @handler.call(self) # Let's step into this line. + + # Make sure that the resulting String to be eval'd is in the + # encoding of the code + source = <<-end_src.dup + def #{method_name}(local_assigns, output_buffer) + _old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code} + ensure + @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer + end + end_src + + # ... + + # source: def _app_views_home_index_html_erb___1187260686135140546_70244801399180(local_assigns, output_buffer) + # _old_virtual_path, @virtual_path = @virtual_path, "home/index";_old_output_buffer = @output_buffer;; + # @output_buffer = output_buffer || ActionView::OutputBuffer.new; + # @output_buffer.safe_append='
+ #

+ # '.freeze; + # @output_buffer.append=( t('home.banner_title') ); + # @output_buffer.append=( @users ); + # @output_buffer.safe_append=' + #

+ #
+ # '.freeze; + # @output_buffer.to_s + # ensure + # @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer + # end + mod.module_eval(source, identifier, 0) # This line will actually define the method '_app_views_home_index_html_erb___1187260686135140546_70244801399180' + # mod: ActionView::CompiledTemplates + ObjectSpace.define_finalizer(self, Finalizer[method_name, mod]) + end + +# .gems/actionview-5.2.2/lib/action_view/template/handler/erb.rb + module Handlers + class ERB + def call(template) + template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT) + + erb = template_source.gsub(ENCODING_TAG, "") + encoding = $2 + + erb.force_encoding valid_encoding(template.source.dup, encoding) + + # Always make sure we return a String in the default_internal + erb.encode! + + self.class.erb_implementation.new( + erb, + escape: (self.class.escape_whitelist.include? template.type), + trim: (self.class.erb_trim_mode == "-") + ).src + end + end + end + end +end +``` + +### How can instance variables defined in Controller be accessed in view file? +It's time to answer the question before: + +How can instance variables like `@users` defined in `HomeController` be accessed in `./app/views/home/index.html.erb`? + +I will answer this question by showing the source code below. +```ruby +# ./gems/actionview-5.2.2/lib/action_view/rendering.rb +module ActionView + module Rendering + def view_context + # view_context_class is a subclass of ActionView::Base. + view_context_class.new( # Let's step into this line later. + view_renderer, + view_assigns, # This line will set the instance variables like '@users' in this example. Let's step into this line. + self + ) + end + + def view_assigns + # self: # + protected_vars = _protected_ivars + # instance_variables is an instance method of class `Object` and it will return an array. And the array contains @users. + variables = instance_variables + + variables.reject! { |s| protected_vars.include? s } + ret = variables.each_with_object({}) { |name, hash| + hash[name.slice(1, name.length)] = instance_variable_get(name) + } + + # ret: {"marked_for_same_origin_verification"=>true, "users"=>[[1, "Lane"], [2, "John"], [4, "Frank"]]} + ret + end + + def view_context_class + # Will return a subclass of ActionView::Base. + @_view_context_class ||= self.class.view_context_class + end + + # How this ClassMethods works? Please look at ActiveSupport::Concern in ./gems/activesupport-5.2.2/lib/active_support/concern.rb + # FYI, the method 'append_features' will be executed automatically before method 'included' executed. + # https://apidock.com/ruby/v1_9_3_392/Module/append_features + module ClassMethods + def view_context_class + # self: HomeController + @view_context_class ||= begin + supports_path = supports_path? + routes = respond_to?(:_routes) && _routes + helpers = respond_to?(:_helpers) && _helpers + + Class.new(ActionView::Base) do + if routes + include routes.url_helpers(supports_path) + include routes.mounted_helpers + end + + if helpers + include helpers + end + end + end + end + end + end +end + +# ./gems/actionview-5.2.2/lib/action_view/base.rb +module ActionView + class Base + def initialize(context = nil, assigns = {}, controller = nil, formats = nil) + @_config = ActiveSupport::InheritableOptions.new + + if context.is_a?(ActionView::Renderer) + @view_renderer = context + else + lookup_context = context.is_a?(ActionView::LookupContext) ? + context : ActionView::LookupContext.new(context) + lookup_context.formats = formats if formats + lookup_context.prefixes = controller._prefixes if controller + @view_renderer = ActionView::Renderer.new(lookup_context) + end + + @cache_hit = {} + + assign(assigns) # Let's step into this line. + + assign_controller(controller) + _prepare_context + end + + def assign(new_assigns) + @_assigns = + new_assigns.each do |key, value| + # This line will set the instance variables (like '@users') in HomeController to itself. + instance_variable_set("@#{key}", value) + end + end + end +end + +``` +After all Rack apps called, user will get the response. + +## Part 4: What does `$ rails server` do? + +If you start Rails by `$ rails server`. You may want to know what does this command do? + +The command `rails` locates at `./bin/`. +```ruby +#!/usr/bin/env ruby +APP_PATH = File.expand_path('../config/application', __dir__) + +require_relative '../config/boot' +require 'rails/commands' # Let's look at this file. +``` + +```ruby +# ./railties-5.2.2/lib/rails/commands.rb +require "rails/command" + +aliases = { + "g" => "generate", + "d" => "destroy", + "c" => "console", + "s" => "server", + "db" => "dbconsole", + "r" => "runner", + "t" => "test" +} + +command = ARGV.shift +command = aliases[command] || command # command is 'server' + +Rails::Command.invoke command, ARGV # Let's step into this line. +``` + +```ruby +# ./railties-5.2.2/lib/rails/command.rb +module Rails + module Command + class << self + def invoke(full_namespace, args = [], **config) + # ... + # command_name: 'server' + # After calling `find_by_namespace`, we will get this result: + # command: Rails::Command::ServerCommand + command = find_by_namespace(namespace, command_name) + + # Equals to: Rails::Command::ServerCommand.perform('server', args, config) + command.perform(command_name, args, config) + end + end + end +end +``` + +```ruby +# ./gems/railties-5.2.2/lib/rails/commands/server/server_command.rb +module Rails + module Command + # There is a class method 'perform' in the Base class. + class ServerCommand < Base + end + end +end +``` + +### Thor +Thor is a toolkit for building powerful command-line interfaces. + +[https://github.com/erikhuda/thor](https://github.com/erikhuda/thor) + +Inheritance relationship: `Rails::Command::ServerCommand < Rails::Command::Base < Thor` + +```ruby +# ./gems/railties-5.2.2/lib/rails/command/base.rb +module Rails + module Command + class Base < Thor + class << self + # command: 'server' + def perform(command, args, config) + #... + dispatch(command, args.dup, nil, config) # Thor.dispatch + end + end + end + end +end +``` + +```ruby +# ./gems/thor-0.20.3/lib/thor.rb +class Thor + class << self + # meth is 'server' + def dispatch(meth, given_args, given_opts, config) + # ... + # Will new a Rails::Command::ServerCommand instance here + # because 'self' is Rails::Command::ServerCommand. + instance = new(args, opts, config) + # ... + # Method 'invoke_command' is defined in Thor::Invocation. + # command: {Thor::Command}# + instance.invoke_command(command, trailing || []) + end + end +end + +# ./gems/thor-0.20.3/lib/thor/invocation.rb +class Thor + # FYI, this module is included in Thor. + # And Thor is grandfather of Rails::Command::ServerCommand + module Invocation + def invoke_command(command, *args) # 'invoke_command' is defined at here. + # ... + # self: # + # command: {Thor::Command}# + command.run(self, *args) + end + end +end + +# ./gems/thor-0.20.3/lib/thor/command.rb +class Thor + class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name) + def run(instance, args = []) + # ... + # instance: # + # name: "server" + # This line will invoke Rails::Command::ServerCommand#server, + # the instance method 'server' is defined in Rails::Command::ServerCommand implicitly. + # I will show you how the instance method 'server' is implicitly defined. + instance.__send__(name, *args) + end + end +end +``` + +```ruby +# ./gems/thor-0.20.3/lib/thor.rb +class Thor + # ... + include Thor::Base # Will invoke hooked method 'Thor::Base.included(self)' +end + +# ./gems/thor-0.20.3/lib/thor/base.rb +module Thor + module Base + class << self + # 'included' is a hooked method. + # When module 'Thor::Base' is included, method 'included' is executed. + def included(base) + # base: Thor + # this line will define `Thor.method_added`. + base.extend ClassMethods + # Module 'Invocation' is included for class 'Thor' here. + # Because Thor is grandfather of Rails::Command::ServerCommand, + # 'invoke_command' will be instance method of Rails::Command::ServerCommand + base.send :include, Invocation # 'invoke_command' is defined in module Invocation + base.send :include, Shell + end + end + + module ClassMethods + # 'method_added' is a hooked method. + # When an instance method is created in Rails::Command::ServerCommand, + # `method_added` will be executed. + # So, when method `perform` is defined in Rails::Command::ServerCommand, + # `method_added` will be executed and create_command('perform') will be invoked. + # So in the end, method 'server' will be created by alias_method('server', 'perform'). + # And the method 'server' is for the 'server' in command `$ rails server`. + def method_added(meth) + # ... + # self: {Class} Rails::Command::ServerCommand + create_command(meth) # meth is 'perform'. Let's step into this line. + end + end + end +end + +# ./gems/railties-5.2.2/lib/rails/command/base.rb +module Rails + module Command + # Rails::Command::Base is superclass of Rails::Command::ServerCommand + module Base + class << self + def create_command(meth) + if meth == "perform" + # Calling instance method 'server' of Rails::Command::ServerCommand + # will be transferred to call instance method 'perform'. + alias_method('server', meth) + end + end + end + end + end +end + +# ./gems/thor-0.20.3/lib/thor/command.rb +class Thor + class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name) + def run(instance, args = []) + #... + # instance: {Rails::Command::ServerCommand}# + # name: 'server'. + # Will actually invoke 'instance.perform(*args)'. + # Equals to invoke Rails::Command::ServerCommand#perform(*args). + # Let's step into Rails::Command::ServerCommand#perform. + instance.__send__(name, *args) + end + end +end + +# ./gems/railties-5.2.2/lib/rails/commands/server/server_command.rb +module Rails + module Command + class ServerCommand < Base + # This is the method will be executed when `$ rails server`. + def perform + # ... + Rails::Server.new(server_options).tap do |server| + # APP_PATH is '/path/to/your_project/config/application'. + # require APP_PATH will create the 'Rails.application' object. + # 'Rails.application' is 'YourProject::Application.new'. + # Rack server will start 'Rails.application'. + require APP_PATH + + Dir.chdir(Rails.application.root) + + server.start # Let's step into this line. + end + end + end + end +end +``` + +### Rails::Server#start +```ruby +# ./gems/railties-5.2.2/lib/rails/commands/server/server_command.rb +module Rails + class Server < ::Rack::Server + def start + print_boot_information + + trap(:INT) do + exit + end + + create_tmp_directories + setup_dev_caching + + # This line is important. Although the method name seems not. + log_to_stdout# Let step into this line. + + super # Will invoke ::Rack::Server#start. I will show you later. + ensure + puts "Exiting" unless @options && options[:daemonize] + end + + def log_to_stdout + # 'wrapped_app' will get an well prepared Rack app from './config.ru' file. + # It's the first time invoke 'wrapped_app'. + # The app is an instance of YourProject::Application. + # But the app is not created in 'wrapped_app'. + # It has been created when `require APP_PATH` in previous code, + # just at the 'perform' method in Rails::Command::ServerCommand. + wrapped_app # Let's step into this line + + # ... + end + end +end + +# ./gems/rack-2.0.6/lib/rack/server.rb +module Rack + class Server + def wrapped_app + @wrapped_app ||= + build_app( + app # Let's step into this line. + ) + end + + def app + @app ||= build_app_and_options_from_config # Let's step into this line. + @app + end + + def build_app_and_options_from_config + # ... + # self.options[:config]: 'config.ru'. Let's step into this line. + app, options = Rack::Builder.parse_file(self.options[:config], opt_parser) + # ... + app + end + + # This method is called in Rails::Server#start + def start(&blk) + #... + wrapped_app + #... + + # server: {Module} Rack::Handler::Puma + # wrapped_app: {YourProject::Application} # + server.run(wrapped_app, options, &blk) # We will step into this line (Rack::Handler::Puma.run) later. + end + end +end + +# ./gems/rack/lib/rack/builder.rb +module Rack + module Builder + def self.parse_file(config, opts = Server::Options.new) + # config: 'config.ru' + cfgfile = ::File.read(config) + + app = new_from_string(cfgfile, config) + + return app, options + end + + # Let's guess what does 'run Rails.application' do in config.ru? + # You may guess that: + # Run YourProject::Application instance. + # But 'run' maybe not what you are thinking about. + # Because the 'self' object in 'config.ru' is #, + # 'run' is an instance method of Rack::Builder. + # Let's look at the definition of the 'run' method: + # def run(app) + # @run = app # Just set an instance variable for Rack::Builder instance. + # end + def self.new_from_string(builder_script, file="(rackup)") + # Rack::Builder implements a small DSL to iteratively construct Rack applications. + eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app", + TOPLEVEL_BINDING, file, 0 + end + end +end +``` + +### Starting Puma +As we see in `Rack::Server#start`, there is `Rack::Handler::Puma.run(wrapped_app, options, &blk)`. + +```ruby +# ./gems/puma-3.12.0/lib/rack/handler/puma.rb +module Rack + module Handler + module Puma + # This method is invoked in `Rack::Server#start`: + # Rack::Handler::Puma.run(wrapped_app, options, &blk) + def self.run(app, options = {}) + conf = self.config(app, options) + + # ... + launcher = ::Puma::Launcher.new(conf, :events => events) + + begin + # Puma will run your app (instance of YourProject::Application) + launcher.run # Let's step into this line. + rescue Interrupt + puts "* Gracefully stopping, waiting for requests to finish" + launcher.stop + puts "* Goodbye!" + end + end + end + end +end + +# .gems/puma-3.12.0/lib/puma/launcher.rb +module Puma + # Puma::Launcher is the single entry point for starting a Puma server based on user + # configuration. It is responsible for taking user supplied arguments and resolving them + # with configuration in `config/puma.rb` or `config/puma/.rb`. + # + # It is responsible for either launching a cluster of Puma workers or a single + # Puma server. + class Launcher + def initialize(conf, launcher_args={}) + @runner = nil + @config = conf + + # ... + if clustered? + # ... + @runner = Cluster.new(self, @events) + else + # For this example, it is Single.new. + @runner = Single.new(self, @events) + end + + # ... + end + + def run + #... + + # Set the behaviors for signals like `$ kill -s SIGTERM puma_process_id` received. + setup_signals # We will discuss this line later. + + set_process_title + + @runner.run # We will enter `Single.new(self, @events).run` here. + + case @status + when :halt + log "* Stopping immediately!" + when :run, :stop + graceful_stop + when :restart + log "* Restarting..." + ENV.replace(previous_env) + @runner.before_restart + restart! + when :exit + # nothing + end + end + end +end +``` + +```ruby +# .gems/puma-3.12.0/lib/puma/single.rb +module Puma + # This class is instantiated by the `Puma::Launcher` and used + # to boot and serve a Ruby application when no puma "workers" are needed + # i.e. only using "threaded" mode. For example `$ puma -t 1:5` + # + # At the core of this class is running an instance of `Puma::Server` which + # gets created via the `start_server` method from the `Puma::Runner` class + # that this inherits from. + class Single < Runner + def run + # ... + + # @server: Puma::Server.new(app, @launcher.events, @options) + @server = server = start_server # Let's step into this line. + + # ... + thread = server.run # Let's step into this line later. + + # This line will suspend the main thread execution. + # And the `thread`'s block (which is method `handle_servers`) will be executed. + # See `Thread#join` for more information. + # I will show you a simple example for using `thread.join`. + # Please search `test_thread_join.rb` in this document. + thread.join + + # The below line will never be executed because `thread` is always running and `thread` has joined. + # When `$ kill -s SIGTERM puma_process_id`, the below line will still not be executed + # because the block of `Signal.trap "SIGTERM"` in `Puma::Launcher#setup_signals` will be executed. + # If you remove the line `thread.join`, the below line will be executed, + # but the main thread will exit after all code executed and all the threads not joined will be killed. + puts "anything which will never be executed..." + end + end +end +``` +```ruby +# .gems/puma-3.12.0/lib/puma/runner.rb +module Puma + # Generic class that is used by `Puma::Cluster` and `Puma::Single` to + # serve requests. This class spawns a new instance of `Puma::Server` via + # a call to `start_server`. + class Runner + def app + @app ||= @launcher.config.app + end + + def start_server + min_t = @options[:min_threads] + max_t = @options[:max_threads] + + server = Puma::Server.new(app, @launcher.events, @options) + server.min_threads = min_t + server.max_threads = max_t + # ... + + server + end + end +end +``` + +```ruby +# .gems/puma-3.12.0/lib/puma/server.rb +module Puma + class Server + def run(background=true) + #... + @status = :run + queue_requests = @queue_requests + + # This part is important. + # Remember the block of ThreadPool.new will be called when a request added to the ThreadPool instance. + # And the block will process the request by calling method `process_client`. + # Let's step into this line later to see how Puma call the block. + @thread_pool = ThreadPool.new(@min_threads, + @max_threads, + IOBuffer) do |client, buffer| + + # Advertise this server into the thread + Thread.current[ThreadLocalKey] = self + + process_now = false + + if queue_requests + process_now = client.eagerly_finish + end + + # ... + if process_now + # Process the request. You can look upon `client` as request. + # If you want to know more about 'process_client', please read part 3 + # or search 'process_client' in this document. + process_client(client, buffer) + else + client.set_timeout @first_data_timeout + @reactor.add client + end + end + + # ... + + if background # background: true (for this example) + # This part is important. + # Remember Puma created a thread here! + # We will know that the newly created thread's job is waiting for requests. + # When a request comes, the thread will transfer the request processing work to a thread in ThreadPool. + # The method `handle_servers` in thread's block will be executed immediately + # (executed in the newly created thread, not in the main thread). + @thread = Thread.new { handle_servers } # Let's step into this line to see what I said. + return @thread + else + handle_servers + end + end + + def handle_servers + sockets = [check] + @binder.ios + pool = @thread_pool + queue_requests = @queue_requests + + # ... + + # The thread is always running, because @status has been set to :run in Puma::Server#run. + # Yes, it should always be running to transfer the incoming requests. + while @status == :run + begin + # This line will cause current thread waiting until a request arrives. + # So it will be the entry of every request! + # sockets: [#, #] + ios = IO.select sockets + + ios.first.each do |sock| + if sock == check + break if handle_check + else + if io = sock.accept_nonblock + # You can simply look upon a Puma::Client instance as a request. + client = Client.new(io, @binder.env(sock)) + + # ... + + # FYI, the method '<<' is redefined. + # Add the request (client) to thread pool means + # a thread in the pool will process this request (client). + pool << client # Let's step into this line. + + pool.wait_until_not_full # Let's step into this line later. + end + end + end + rescue Object => e + @events.unknown_error self, e, "Listen loop" + end + end + end + end +end +``` + +```ruby +# .gems/puma-3.12.0/lib/puma/thread_pool.rb +module Puma + class ThreadPool + # Maintain a minimum of +min+ and maximum of +max+ threads + # in the pool. + # + # The block passed is the work that will be performed in each + # thread. + # + def initialize(min, max, *extra, &block) + #.. + @mutex = Mutex.new + @todo = [] # @todo is requests (in Puma, they are Puma::Client instances) which need to be processed. + @spawned = 0 # the count of @spawned threads + @min = Integer(min) # @min threads count + @max = Integer(max) # @max threads count + @block = block # block will be called in method `spawn_thread` to processed a request. + @workers = [] + @reaper = nil + + @mutex.synchronize do + @min.times { spawn_thread } # Puma spawns @min count threads. + end + end + + def spawn_thread + @spawned += 1 + + # Create a new Thread now. + # The block of the thread will be executed immediately and separately from the calling thread (main thread). + th = Thread.new(@spawned) do |spawned| + # Thread name is new in Ruby 2.3 + Thread.current.name = 'puma %03i' % spawned if Thread.current.respond_to?(:name=) + block = @block + mutex = @mutex + #... + + extra = @extra.map { |i| i.new } + + # Pay attention to here: + # 'while true' means this part will always be running. + # And there will be @min count threads always running! + # Puma uses these threads to process requests. + # The line: 'not_empty.wait(mutex)' will make current thread waiting. + while true + work = nil + + continue = true + + mutex.synchronize do + while todo.empty? + if @trim_requested > 0 + @trim_requested -= 1 + continue = false + not_full.signal + break + end + + if @shutdown + continue = false + break + end + + @waiting += 1 # `@waiting` is the waiting threads count. + not_full.signal + + # This line will cause current thread waiting + # until `not_empty.signal` executed in some other place to wake it up . + # Actually, `not_empty.signal` is located at `def <<(work)` in the same file. + # You can search `def <<(work)` in this document. + # Method `<<` is used in method `handle_servers`: `pool << client` in Puma::Server#run. + # `pool << client` means add a request to the thread pool, + # and then the waked up thread will process the request. + not_empty.wait mutex + + @waiting -= 1 + end + + # `work` is the request (in Puma, it's Puma::Client instance) which need to be processed. + work = todo.shift if continue + end + + break unless continue + + if @clean_thread_locals + ThreadPool.clean_thread_locals + end + + begin + # `block.call` will switch program to the block definition part. + # The block definition part is in `Puma::Server#run`: + # @thread_pool = ThreadPool.new(@min_threads, + # @max_threads, + # IOBuffer) do |client, buffer| #...; end + # So please search `ThreadPool.new` in this document to look back. + block.call(work, *extra) + rescue Exception => e + STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})" + end + end + + mutex.synchronize do + @spawned -= 1 + @workers.delete th + end + end # end of the Thread.new. + + @workers << th + + th + end + + def wait_until_not_full + @mutex.synchronize do + while true + return if @shutdown + + # If we can still spin up new threads and there + # is work queued that cannot be handled by waiting + # threads, then accept more work until we would + # spin up the max number of threads. + return if @todo.size - @waiting < @max - @spawned + + @not_full.wait @mutex + end + end + end + + # Add +work+ to the todo list for a Thread to pickup and process. + def <<(work) + @mutex.synchronize do + if @shutdown + raise "Unable to add work while shutting down" + end + + # work: # + # You can look upon Puma::Client instance as a request. + @todo << work + + if @waiting < @todo.size and @spawned < @max + spawn_thread # Create one more thread to process request. + end + + # Wake up the waiting thread to process the request. + # The waiting thread is defined in the same file: Puma::ThreadPool#spawn_thread. + # This code is in `spawn_thread`: + # while true + # # ... + # not_empty.wait mutex + # # ... + # block.call(work, *extra) # This line will process the request. + # end + @not_empty.signal + end + end + end +end +``` + +### Conclusion +In conclusion, `$ rails server` will execute `Rails::Command::ServerCommand#perform`. + +In `#perform`, call `Rails::Server#start`. Then call `Rack::Server#start`. + +Then call `Rack::Handler::Puma.run(YourProject::Application.new)`. + +In `.run`, Puma will new a always running Thread for `ios = IO.select(#)`. + +Request is created from `ios` object. + +A thread in Puma threadPool will process the request. + +The thread will invoke Rack apps' `call` to get the response for the request. + +### Exiting Puma +#### Process and Thread +Because Puma is using multiple threads, we need to have some basic concepts about Process and Thread. + +This link is good for you to obtain the concepts: [Process and Thread](https://stackoverflow.com/questions/4894609/will-a-cpu-process-have-at-least-one-thread) + +In the next part, you will often see `thread.join`. + +I will use two simple example to tell what does `thread.join` do. + +##### Example one +Try to run `test_thread_join.rb`. + +```ruby +# ./test_thread_join.rb +thread = Thread.new() do + 3.times do |n| + puts "~~~~ " + n.to_s + end +end + +# sleep 1 +puts "==== I am the main thread." + +# thread.join # Try to uncomment these two lines to see the differences. +# puts "==== after thread.join" +``` +You will find that if there is no `thread.join`, you can see +```log +==== I am the main thread. +==== after thread.join +~~~~ 0 +~~~~ 1 +~~~~ 2 +``` +in console. + +After you added `thread.join`, you can see: +```log +==== I am the main thread. +~~~~ 0 +~~~~ 1 +~~~~ 2 +==== after thread.join +```` +in console. + +##### Example two +Try to run `test_thread_join2.rb`. +```ruby +# ./test_thread_join2.rb +arr = [ + Thread.new do + puts 'I am arr[0]' + sleep 1 + puts 'After arr[0]' + end, + Thread.new do + puts 'I am arr[1]' + sleep 5 + puts 'After arr[1]' + end, + Thread.new do + puts 'I am arr[2]' + sleep 8 + puts 'After arr[2]' + end +] + +puts "Thread.list.size: #{Thread.list.size}" # returns 4 (including the main thread) + +sleep 2 + +arr.each { |thread| puts "~~~~~ #{thread}" } + +puts "Thread.list.size: #{Thread.list.size}" # returns 3 (because arr[0] is dead) + +arr[1].join # uncomment to see differences + +arr.each { |thread| puts "~~~~~ #{thread}" } + +sleep 7 +puts "Exit main thread" +``` + +#### Send `SIGTERM` to Puma +When you stop Puma by running `$ kill -s SIGTERM puma_process_id`, you will enter `setup_signals` in `Puma::Launcher#run`. +```ruby +# .gems/puma-3.12.0/lib/puma/launcher.rb +module Puma + # Puma::Launcher is the single entry point for starting a Puma server based on user + # configuration. + class Launcher + def run + #... + + # Set the behaviors for signals like `$ kill -s SIGTERM puma_process_id`. + setup_signals # Let's step into this line. + + set_process_title + + @runner.run + + # ... + end + + # Set the behaviors for signals like `$ kill -s SIGTERM puma_process_id`. + # Signal.list #=> {"EXIT"=>0, "HUP"=>1, "INT"=>2, "QUIT"=>3, "ILL"=>4, "TRAP"=>5, "IOT"=>6, "ABRT"=>6, "FPE"=>8, "KILL"=>9, "BUS"=>7, "SEGV"=>11, "SYS"=>31, "PIPE"=>13, "ALRM"=>14, "TERM"=>15, "URG"=>23, "STOP"=>19, "TSTP"=>20, "CONT"=>18, "CHLD"=>17, "CLD"=>17, "TTIN"=>21, "TTOU"=>22, "IO"=>29, "XCPU"=>24, "XFSZ"=>25, "VTALRM"=>26, "PROF"=>27, "WINCH"=>28, "USR1"=>10, "USR2"=>12, "PWR"=>30, "POLL"=>29} + # Press `Control + C` to quit means 'SIGINT'. + def setup_signals + begin + # After running `$ kill -s SIGTERM puma_process_id`, Ruby will execute the block of `Signal.trap "SIGTERM"`. + Signal.trap "SIGTERM" do + graceful_stop # Let's step into this line. + + raise SignalException, "SIGTERM" + end + rescue Exception + log "*** SIGTERM not implemented, signal based gracefully stopping unavailable!" + end + + begin + Signal.trap "SIGUSR2" do + restart + end + rescue Exception + log "*** SIGUSR2 not implemented, signal based restart unavailable!" + end + + begin + Signal.trap "SIGUSR1" do + phased_restart + end + rescue Exception + log "*** SIGUSR1 not implemented, signal based restart unavailable!" + end + + begin + Signal.trap "SIGINT" do + if Puma.jruby? + @status = :exit + graceful_stop + exit + end + + stop + end + rescue Exception + log "*** SIGINT not implemented, signal based gracefully stopping unavailable!" + end + + begin + Signal.trap "SIGHUP" do + if @runner.redirected_io? + @runner.redirect_io + else + stop + end + end + rescue Exception + log "*** SIGHUP not implemented, signal based logs reopening unavailable!" + end + end + + def graceful_stop + # @runner: instance of Puma::Single (for this example) + @runner.stop_blocked # Let's step into this line. + log "=== puma shutdown: #{Time.now} ===" + log "- Goodbye!" + end + end +end + +# .gems/puma-3.12.0/lib/puma/launcher.rb +module Puma + class Single < Runner + def run + # ... + + # @server: Puma::Server.new(app, @launcher.events, @options) + @server = server = start_server # Let's step into this line. + + # ... + thread = server.run + + # This line will suspend the main thread execution. + # And the `thread`'s block (which is the method `handle_servers`) will be executed. + thread.join + end + + def stop_blocked + log "- Gracefully stopping, waiting for requests to finish" + @control.stop(true) if @control + # @server: instance of Puma::Server + @server.stop(true) # Let's step into this line + end + end +end + +# .gems/puma-3.12.0/lib/puma/server.rb +module Puma + class Server + def initialize(app, events=Events.stdio, options={}) + # 'Puma::Util.pipe' returns `IO.pipe`. + @check, @notify = Puma::Util.pipe # @check, @notify is a pair. + + @status = :stop + end + + def run(background=true) + # ... + @thread_pool = ThreadPool.new(@min_threads, + @max_threads, + IOBuffer) do |client, buffer| + + #... + # Process the request. + process_client(client, buffer) + #... + end + + # 'Thread.current.object_id' returns '70144214949920', + # which is the same as the 'Thread.current.object_id' in Puma::Server#stop. + # Current thread is the main thread here. + puts "#{Thread.current.object_id}" + + # The created @thread is the @thread in `stop` method below. + @thread = Thread.new { + # FYI, this is in the Puma starting process. + # 'Thread.current.object_id' returns '70144220123860', + # which is the same as the 'Thread.current.object_id' in 'handle_servers' in Puma::Server#run + # def handle_servers + # begin + # # ... + # ensure + # # FYI, the 'ensure' part is in the Puma stopping process. + # puts "#{Thread.current.object_id}" # returns '70144220123860' too. + # end + # end + puts "#{Thread.current.object_id}" # returns '70144220123860' + + handle_servers + } + return @thread + end + + # Stops the acceptor thread and then causes the worker threads to finish + # off the request queue before finally exiting. + def stop(sync=false) + # This line will set '@status = :stop', + # and cause `ios = IO.select sockets` (in method `handle_servers`) to return result. + # So that the code after `ios = IO.select sockets` will be executed. + notify_safely(STOP_COMMAND) # Let's step into this line. + + # 'Thread.current.object_id' returns '70144214949920', + # which is the same as the 'Thread.current.object_id' in Puma::Server#run. + # Current thread is exactly the main thread here. + puts "#{Thread.current.object_id}" + + # The @thread is just the always running Thread created in `Puma::Server#run`. + # Please look at method `Puma::Server#run`. + # `@thread.join` will suspend the main thread execution. + # And the code in @thread will continue be executed. + @thread.join if @thread && sync + end + + def notify_safely(message) + @notify << message + end + + def handle_servers + begin + check = @check + # sockets: [#, #] + sockets = [check] + @binder.ios + pool = @thread_pool + #... + + while @status == :run + # After `notify_safely(STOP_COMMAND)` in main thread, `ios = IO.select sockets` will return result. + # FYI, `@check, @notify = IO.pipe`. + # def notify_safely(message) + # @notify << message + # end + # sockets: [#, #] + ios = IO.select sockets + + ios.first.each do |sock| + if sock == check + # The @status is updated to :stop for this example in `handle_check`. + break if handle_check # Let's step into this line. + else + if io = sock.accept_nonblock + client = Client.new(io, @binder.env(sock)) + + # ... + pool << client + pool.wait_until_not_full + end + end + end + end + + # Let's step into `graceful_shutdown`. + graceful_shutdown if @status == :stop || @status == :restart + + # ... + ensure + # FYI, the 'ensure' part is in the Puma stopping process. + # 'Thread.current.object_id' returns '70144220123860', + # which is the same as the 'Thread.current.object_id' in 'Thread.new block' in Puma::Server#run + # @thread = Thread.new do + # # FYI, this is in the Puma starting process. + # puts "#{Thread.current.object_id}" # returns '70144220123860' + # handle_servers + # end + puts "#{Thread.current.object_id}" + + @check.close + @notify.close + + # ... + end + end + + def handle_check + cmd = @check.read(1) + + case cmd + when STOP_COMMAND + @status = :stop # The @status is updated to :stop for this example. + return true + when HALT_COMMAND + @status = :halt + return true + when RESTART_COMMAND + @status = :restart + return true + end + + return false + end + + def graceful_shutdown + if @thread_pool + @thread_pool.shutdown # Let's step into this line. + end + end + end +end +``` + +```ruby +module Puma + class ThreadPool + # Tell all threads in the pool to exit and wait for them to finish. + def shutdown(timeout=-1) + threads = @mutex.synchronize do + @shutdown = true + # `broadcast` will wakes up all threads waiting for this lock. + @not_empty.broadcast + @not_full.broadcast + + # ... + + # dup workers so that we join them all safely + # @workers is an array. + # @workers.dup will not create new thread. + # @workers is an instance variable and will be changed when shutdown (by `@workers.delete th`). + # So ues @workers.dup here. + @workers.dup + end + + # Wait for threads to finish without force shutdown. + threads.each do |thread| + thread.join + end + + @spawned = 0 + @workers = [] + end + + def initialize(min, max, *extra, &block) + #.. + @mutex = Mutex.new + @spawned = 0 # The count of @spawned threads. + @todo = [] # @todo is requests (in Puma, it's Puma::Client instance) which need to be processed. + @min = Integer(min) # @min threads count + @block = block # block will be called in method `spawn_thread` to process a request. + @workers = [] + + @mutex.synchronize do + @min.times { spawn_thread } # Puma spawns @min count threads. + end + end + + def spawn_thread + @spawned += 1 + + # Run a new Thread now. + # The block of the thread will be executed separately from the calling thread. + th = Thread.new(@spawned) do |spawned| + block = @block + mutex = @mutex + #... + + while true + work = nil + + continue = true + + mutex.synchronize do + while todo.empty? + # ... + + if @shutdown + continue = false + break + end + + # ... + # After `@not_empty.broadcast` is executed in '#shutdown', `not_empty` is waked up. + # Ruby will continue to execute the next line here. + not_empty.wait mutex + + @waiting -= 1 + end + + # ... + end + + break unless continue + + # ... + end + + mutex.synchronize do + @spawned -= 1 + @workers.delete th + end + end # end of the Thread.new. + + @workers << th + + th + end + end +end +``` + +So all the threads in the ThreadPool joined and finished. + +Let's inspect the caller in block of `Signal.trap "SIGTERM"` below. + +```ruby +# .gems/puma-3.12.0/lib/puma/launcher.rb +module Puma + # Puma::Launcher is the single entry point for starting a Puma server based on user + # configuration. + class Launcher + def run + #... + + # Set the behaviors for signals like `$ kill -s SIGTERM puma_process_id`. + setup_signals # Let's step into this line. + + set_process_title + + # Process.pid: 42264 + puts "Process.pid: #{Process.pid}" + + @runner.run + + # ... + end + + def setup_signals + # ... + begin + # After running `$ kill -s SIGTERM puma_process_id`, Ruby will execute the block of `Signal.trap "SIGTERM"`. + Signal.trap "SIGTERM" do + # I inspect `caller` to see the caller stack. + # caller: [ + # "../gems/puma-3.12.0/lib/puma/single.rb:118:in `join'", + # "../gems/puma-3.12.0/lib/puma/single.rb:118:in `run'", + # "../gems/puma-3.12.0/lib/puma/launcher.rb:186:in `run'", + # "../gems/puma-3.12.0/lib/rack/handler/puma.rb:70:in `run'", + # "../gems/rack-2.0.6/lib/rack/server.rb:298:in `start'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:55:in `start'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:149:in `block in perform'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:144:in `tap'", + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:144:in `perform'", + # "../gems/thor-0.20.3/lib/thor/command.rb:27:in `run'", + # "../gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'", + # "../gems/thor-0.20.3/lib/thor.rb:391:in `dispatch'", + # "../gems/railties-5.2.2/lib/rails/command/base.rb:65:in `perform'", + # "../gems/railties-5.2.2/lib/rails/command.rb:46:in `invoke'", + # "../gems/railties-5.2.2/lib/rails/commands.rb:18:in `'", + # "../path/to/your_project/bin/rails:5:in `require'", + # "../path/to/your_project/bin/rails:5:in `
'" + # ] + puts "caller: #{caller.inspect}" + + # Process.pid: 42264 which is the same as the `Process.pid` in the Puma::Launcher#run. + puts "Process.pid: #{Process.pid}" + + graceful_stop + + # This SignalException is not rescued in the caller stack. + # So in the the caller stack, Ruby will goto the `ensure` part in + # "../gems/railties-5.2.2/lib/rails/commands/server/server_command.rb:55:in `start'". + # So the last code executed is `puts "Exiting" unless @options && options[:daemonize]` + # when running `$ kill -s SIGTERM puma_process_id`. + # You can search `puts "Exiting"` in this document to see it. + raise SignalException, "SIGTERM" + end + rescue Exception + # This `rescue` is only for `Signal.trap "SIGTERM"`, not for `raise SignalException, "SIGTERM"`. + log "*** SIGTERM not implemented, signal based gracefully stopping unavailable!" + end + end + end +end +``` + +Welcome to point out the mistakes in this article :) -# leetcode-python-java - -**Not only** Python & Java solutions for LeetCode problems, but also => - -## LeetCode Python/Java/JavaScript/C#/Go/Ruby Solutions - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Hi there! I'm Lane. -Do you feel that there are too many problems (over 3,450) on the LeetCode and you can't finish them all? -Or do you forget how to solve the problems you did last time? - -If you can master some solution patterns, this will happen less often. - -Here, I will provide you with **common problem-solving patterns** so that you don't waste time on problems that are not often tested in interviews. - -**Python, C++, Java, JavaScript, C#, Go, Ruby** languages' solutions are provided for every selected LeetCode problem. Other languages' solutions will be provided in the future. If you have better solutions, welcome to create an issue or PR! - -## How to fully demonstrate your abilities to employers and get the offer you want? - -[Personal Brand Website Builder](https://github.com/PersonalBranding/personal-brand-website-builder) focuses on bringing value to developers, including resume, portfolio, blog and other functions. With it, your abilities will be better seen by employers! - -## How to Use this "leetcode-python-java" Repository? - -I have planned a learning route for you. You just need to do the problems in the order they are listed. -You can skip the more difficult problems and do them later. - -## Array -- [344. Reverse String](en/1-1000/344-reverse-string.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [27. Remove Element](en/1-1000/27-remove-element.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **2** approaches. -- [605. Can Place Flowers](en/1-1000/605-can-place-flowers.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [238. Product of Array Except Self](en/1-1000/238-product-of-array-except-self.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [704. Binary Search](en/1-1000/704-binary-search.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [977. Squares of a Sorted Array](en/1-1000/977-squares-of-a-sorted-array.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [209. Minimum Size Subarray Sum](en/1-1000/209-minimum-size-subarray-sum.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [303. Range Sum Query - Immutable](en/1-1000/303-range-sum-query-immutable.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [59. Spiral Matrix II](en/1-1000/59-spiral-matrix-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [503. Next Greater Element II](en/1-1000/503-next-greater-element-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [3478. Choose K Elements With Maximum Sum](https://leetcode.blog/en/leetcode/3478-choose-k-elements-with-maximum-sum) Python. - -## Linked List -- [203. Remove Linked List Elements](en/1-1000/203-remove-linked-list-elements.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [206. Reverse Linked List](en/1-1000/206-reverse-linked-list.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [160. Intersection of Two Linked Lists](en/1-1000/160-intersection-of-two-linked-lists.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [19. Remove Nth Node From End of List](en/1-1000/19-remove-nth-node-from-end-of-list.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [707. Design Linked List](en/1-1000/707-design-linked-list.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [24. Swap Nodes in Pairs](en/1-1000/24-swap-nodes-in-pairs.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -## Hash Table -- [349. Intersection of Two Arrays](en/1-1000/349-intersection-of-two-arrays.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [242. Valid Anagram](en/1-1000/242-valid-anagram.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [1. Two Sum](en/1-1000/1-two-sum.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [383. Ransom Note](en/1-1000/383-ransom-note.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [202. Happy Number](en/1-1000/202-happy-number.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [454. 4Sum II](en/1-1000/454-4sum-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [49. Group Anagrams](https://leetcode.blog/en/leetcode/49-group-anagrams) Python, Ruby. - -## String -- [28. Find the Index of the First Occurrence in a String](en/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [541. Reverse String II](en/1-1000/541-reverse-string-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [1768. Merge Strings Alternately](en/1001-2000/1768-merge-strings-alternately.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [1431. Kids With the Greatest Number of Candies](en/1001-2000/1431-kids-with-the-greatest-number-of-candies.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [151. Reverse Words in a String](en/1-1000/151-reverse-words-in-a-string.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [459. Repeated Substring Pattern](en/1-1000/459-repeated-substring-pattern.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [833. Find, Replace in String](https://leetcode.blog/en/leetcode/833-find-and-replace-in-string) Python. -- [1071. Greatest Common Divisor of Strings](en/1001-2000/1071-greatest-common-divisor-of-strings.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -## Two Pointers -- [345. Reverse Vowels of a String](en/1-1000/345-reverse-vowels-of-a-string.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [15. 3Sum](en/1-1000/15-3sum.md) Python, Java, C++, JavaScript, C#, Go, Ruby, 2 approaches. -- [18. 4Sum](en/1-1000/18-4sum.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -## Stack & Queue -- [20. Valid Parentheses](en/1-1000/20-valid-parentheses.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [232. Implement Queue using Stacks](en/1-1000/232-implement-queue-using-stacks.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [225. Implement Stack using Queues](en/1-1000/225-implement-stack-using-queues.md) Python, Java, C++, JavaScript, C#, Go, Ruby, 3 approaches. - -## Binary Tree -- [144. Binary Tree Preorder Traversal](en/1-1000/144-binary-tree-preorder-traversal.md) Python, 2 approaches. - -## Dynamic Programming -### Easy Problems -- [509. Fibonacci Number](en/1-1000/509-fibonacci-number.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -### House Robber -- [198. House Robber](en/1-1000/198-house-robber.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [213. House Robber II](en/1-1000/213-house-robber-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [337. House Robber III](en/1-1000/337-house-robber-iii.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **2** approaches. - -### Knapsack Problems -#### 0/1 Knapsack -- [416. Partition Equal Subset Sum](en/1-1000/416-partition-equal-subset-sum.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **2** approaches. -- [1049. Last Stone Weight II](en/1001-2000/1049-last-stone-weight-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **2** approaches. -- [494. Target Sum](en/1-1000/494-target-sum.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [474. Ones and Zeroes](en/1-1000/474-ones-and-zeroes.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -#### Unbounded Knapsack -- [518. Coin Change II](en/1-1000/518-coin-change-ii.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [377. Combination Sum IV](en/1-1000/377-combination-sum-iv.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [322. Coin Change](en/1-1000/322-coin-change.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [279. Perfect Squares](en/1-1000/279-perfect-squares.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [139. Word Break](en/1-1000/139-word-break.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -### Stock Maximum Profit Problems -- [121. Best Time to Buy and Sell Stock](en/1-1000/121-best-time-to-buy-and-sell-stock.md) Python, JavaScript, Go. -- [122. Best Time to Buy and Sell Stock II](en/1-1000/122-best-time-to-buy-and-sell-stock-ii.md) Python, JavaScript, Go. -- [714. Best Time to Buy and Sell Stock with Transaction Fee](en/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md) Python, JavaScript, Go. -- [123. Best Time to Buy and Sell Stock III](en/1-1000/123-best-time-to-buy-and-sell-stock-iii.md) Python, JavaScript, Go. -- [188. Best Time to Buy and Sell Stock IV](en/1-1000/188-best-time-to-buy-and-sell-stock-iv.md) Python, JavaScript, Go. -- [309. Best Time to Buy and Sell Stock with Cooldown](en/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md) Python, JavaScript, Go. - -### Subsequence Problems -- [674. Longest Continuous Increasing Subsequence](en/1-1000/674-longest-continuous-increasing-subsequence.md) Python, Java, JavaScript, C#. -- [300. Longest Increasing Subsequence](en/1-1000/300-longest-increasing-subsequence.md) Python, Java, JavaScript, C#. -- [718. Maximum Length of Repeated Subarray](en/1-1000/718-maximum-length-of-repeated-subarray.md) Python, Java, JavaScript, C#. -- [1143. Longest Common Subsequence](en/1001-2000/1143-longest-common-subsequence.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [1035. Uncrossed Lines](en/1001-2000/1035-uncrossed-lines.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [53. Maximum Subarray](en/1-1000/53-maximum-subarray.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [392. Is Subsequence](en/1-1000/392-is-subsequence.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [583. Delete Operation for Two Strings](en/1-1000/583-delete-operation-for-two-strings.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [72. Edit Distance](en/1-1000/72-edit-distance.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -### Hard Problems -- [3494. Find the Minimum Amount of Time to Brew Potions](https://leetcodepython.com/en/leetcode/3494-find-the-minimum-amount-of-time-to-brew-potions) Python, Java, C++, JavaScript, C#, Go, Ruby. - -## Monotonic Stack -- [739. Daily Temperatures](en/1-1000/739-daily-temperatures.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [496. Next Greater Element I](en/1-1000/496-next-greater-element-i.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [42. Trapping Rain Water](en/1-1000/42-trapping-rain-water.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [84. Largest Rectangle in Histogram](en/1-1000/84-largest-rectangle-in-histogram.md) Python, Java, C++, JavaScript, C#, Go, Ruby. - -## Graph Theory -- [797. All Paths From Source to Target](en/1-1000/797-all-paths-from-source-to-target.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **2** approaches. -- [200. Number of Islands](en/1-1000/200-number-of-islands.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **3** approaches. -- [463. Island Perimeter](en/1-1000/463-island-perimeter.md) Python, **2** approaches. -- [695. Max Area of Island](en/1-1000/695-max-area-of-island.md) Python, Java, C++, JavaScript, C#, Go, Ruby, **3** approaches. -- [827. Making A Large Island](en/1-1000/827-making-a-large-island.md) Python, **2** approaches. -- [127. Word Ladder](en/1-1000/127-word-ladder.md) Python. -- [1971. Find if Path Exists in Graph](en/1001-2000/1971-find-if-path-exists-in-graph.md) Python, Java, C++, JavaScript, C#, Go, Ruby, 2 approaches. -- [684. Redundant Connection](en/1-1000/684-redundant-connection.md) Python, Java, C++, JavaScript, C#, Go, Ruby. -- [685. Redundant Connection II](en/1-1000/685-redundant-connection-ii.md) Python. -- [1584. Min Cost to Connect All Points](en/1001-2000/1584-min-cost-to-connect-all-points.md) Python, Java, C++, JavaScript, C#, Go, Ruby, 2 approaches. -- [207. Course Schedule](en/1-1000/207-course-schedule.md) Python, Java, C++, C#, 2 approaches. -- [1514. Path with Maximum Probability](en/1001-2000/1514-path-with-maximum-probability.md) Python, 2 approaches. -- [752. Open the Lock](en/1-1000/752-open-the-lock.md) Python, 2 approaches. -- [743. Network Delay Time](en/1-1000/743-network-delay-time.md) Python, 2 approaches. -- [787. Cheapest Flights Within K Stops](en/1-1000/787-cheapest-flights-within-k-stops.md) Python. -- [1334. Find the City With the Smallest Number of Neighbors at a Threshold Distance](en/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md) Python. - -## Other Algorithms -- [433. Minimum Genetic Mutation](en/1-1000/433-minimum-genetic-mutation.md) Python, 3 approaches. - -## "leetcode-python-java": More Problems - -More LeetCode problems and solutions will be added soon. Updated every day. diff --git a/en/1-1000/1-two-sum.md b/en/1-1000/1-two-sum.md deleted file mode 100644 index 325e61a..0000000 --- a/en/1-1000/1-two-sum.md +++ /dev/null @@ -1,331 +0,0 @@ -# 1. Two Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [1. Two Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1-two-sum) for a better experience! - -LeetCode link: [1. Two Sum](https://leetcode.com/problems/two-sum), difficulty: **Easy**. - -## LeetCode description of "1. Two Sum" - -Given an array of integers `nums` and an integer `target`, return *indices of the two numbers such that they add up to `target`*. - -You may assume that each input would have ***exactly* one solution**, and you may not use the same element twice. - -You can return the answer in any order. - -### [Example 1] - -**Input**: `nums = [2,7,11,15], target = 9` - -**Output**: `[0,1]` - -**Explanation**: - -

Because nums[0] + nums[1] == 9, we return [0, 1].

- - -### [Example 2] - -**Input**: `nums = [3,2,4], target = 6` - -**Output**: `[1,2]` - -### [Example 3] - -**Input**: `nums = [3,3], target = 6` - -**Output**: `[0,1]` - -### [Constraints] - -- `2 <= nums.length <= 10^4` -- `-10^9 <= nums[i] <= 10^9` -- `-10^9 <= target <= 10^9` -- **Only one valid answer exists.** - -### [Hints] - -
- Hint 1 - A really brute force way would be to search for all possible pairs of numbers but that would be too slow. Again, it's best to try out brute force solutions for just for completeness. It is from these brute force solutions that you can come up with optimizations. - - -
- -
- Hint 2 - So, if we fix one of the numbers, say `x`, we have to scan the entire array to find the next number `y` which is `value - x` where value is the input parameter. Can we change our array somehow so that this search becomes faster? - - -
- -
- Hint 3 - The second train of thought is, without changing the array, can we use additional space somehow? Like maybe a hash map to speed up the search? - - -
- -## Intuition 1 - -1. The time complexity of the brute force solution is `O(n^2)`. To improve efficiency, you can sort the array, and then use **two pointers**, one pointing to the head of the array and the other pointing to the tail of the array, and decide `left += 1` or `right -= 1` according to the comparison of `sum` and `target`. - -2. After sorting an array of numbers, if you want to know the original `index` corresponding to a certain value, there are two solutions: - -
Click to view the answer

- - Solution 1: Bring the `index` when sorting, that is, the object to be sorted is an array of tuples of `(num, index)`. This technique **must be mastered**, as it will be used in many questions. - - Solution 2: Use `index()` method to find it. I have discussed this in another solution. -

- -## Complexity - -- Time complexity: `O(N * log N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - num_index_list = [(num, i) for i, num in enumerate(nums)] - num_index_list.sort() - - left = 0 - right = len(nums) - 1 - - while left < right: - sum_ = num_index_list[left][0] + num_index_list[right][0] - - if sum_ == target: - return [num_index_list[left][1], num_index_list[right][1]] - - if sum_ < target: - left += 1 - continue - - right -= 1 -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -1. In `Map`, `key` is `num`, and `value` is array `index`. -2. Traverse the array, if `target - num` is in `Map`, return it. Otherwise, add `num` to `Map`. - -## Step by Step Solutions - -1. In `Map`, `key` is `num`, and `value` is array `index`. - - ```javascript - let numToIndex = new Map() - - for (let i = 0; i < nums.length; i++) { - numToIndex.set(nums[i], i) - } - ``` - -2. Traverse the array, if `target - num` is in `Map`, return it. Otherwise, add `num` to `Map`. - - ```javascript - let numToIndex = new Map() - - for (let i = 0; i < nums.length; i++) { - if (numToIndex.has(target - nums[i])) { // 1 - return [numToIndex.get(target - nums[i]), i] // 2 - } - - numToIndex.set(nums[i], i) - } - ``` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public int[] twoSum(int[] nums, int target) { - var numToIndex = new HashMap(); - - for (var i = 0; i < nums.length; i++) { - if (numToIndex.containsKey(target - nums[i])) { - return new int[]{numToIndex.get(target - nums[i]), i}; - } - - numToIndex.put(nums[i], i); - } - - return null; - } -} -``` - -## Python - -```python -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - num_to_index = {} - - for i, num in enumerate(nums): - if target - num in num_to_index: - return [num_to_index[target - num], i] - - num_to_index[num] = i -``` - -## C++ - -```cpp -class Solution { -public: - vector twoSum(vector& nums, int target) { - unordered_map num_to_index; - - for (auto i = 0; i < nums.size(); i++) { - if (num_to_index.contains(target - nums[i])) { - return {num_to_index[target - nums[i]], i}; - } - - num_to_index[nums[i]] = i; - } - - return {}; - } -}; -``` - -## JavaScript - -```javascript -var twoSum = function (nums, target) { - let numToIndex = new Map() - - for (let i = 0; i < nums.length; i++) { - if (numToIndex.has(target - nums[i])) { - return [numToIndex.get(target - nums[i]), i] - } - - numToIndex.set(nums[i], i) - } -}; -``` - -## C# - -```csharp -public class Solution { - public int[] TwoSum(int[] nums, int target) { - var numToIndex = new Dictionary(); - - for (int i = 0; i < nums.Length; i++) { - if (numToIndex.ContainsKey(target - nums[i])) { - return [numToIndex[target - nums[i]], i]; - } - - numToIndex[nums[i]] = i; - } - - return null; - } -} -``` - -## Go - -```go -func twoSum(nums []int, target int) []int { - numToIndex := map[int]int{} - - for i, num := range nums { - if index, ok := numToIndex[target - num]; ok { - return []int{index, i} - } - - numToIndex[num] = i - } - - return nil -} -``` - -## Ruby - -```ruby -def two_sum(nums, target) - num_to_index = {} - - nums.each_with_index do |num, i| - if num_to_index.key?(target - num) - return [num_to_index[target - num], i] - end - - num_to_index[num] = i - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 3 - -1. The time complexity of the brute force solution is `O(n^2)`. To improve efficiency, you can sort the array, and then use **two pointers**, one pointing to the head of the array and the other pointing to the tail of the array, and decide `left += 1` or `right -= 1` according to the comparison of `sum` and `target`. -2. After finding the two values which `sum` is `target`, you can use the `index()` method to find the `index` corresponding to the value. - -## Complexity - -- Time complexity: `O(N * log N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - original_nums = nums.copy() - nums.sort() - - left = 0 - right = len(nums) - 1 - - while left < right: - sum_ = nums[left] + nums[right] - - if sum_ == target: - break - - if sum_ < target: - left += 1 - continue - - right -= 1 - - return [ - original_nums.index(nums[left]), - len(nums) - 1 - original_nums[::-1].index(nums[right]) - ] -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [1. Two Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1-two-sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/121-best-time-to-buy-and-sell-stock.md b/en/1-1000/121-best-time-to-buy-and-sell-stock.md deleted file mode 100644 index 852c919..0000000 --- a/en/1-1000/121-best-time-to-buy-and-sell-stock.md +++ /dev/null @@ -1,124 +0,0 @@ -# 121. Best Time to Buy and Sell Stock (Dynamic Programming Solution) -LeetCode link: [121. Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -You want to **maximize** your profit by choosing **a single day** to buy one stock and choosing **a different day** in the future to sell that stock. - -Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return `0`. - -### [Example 1] -**Input**: `prices = [7,1,5,3,6,4]` - -**Output**: `5` - -**Explanation** -``` -Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. -Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell. -``` - -### [Example 2] -**Input**: `prices = [7,6,4,3,1]` - -**Output**: `0` - -**Explanation**: `In this case, no transactions are done and the max profit = 0.` - -### [Constraints] -- `1 <= prices.length <= 100000` -- `0 <= prices[i] <= 10000` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - # states: - # 0: hold stock - # 1) keep holding - # 2) today just bought - # 1: no stock - # 1) keep no stock - # 2) today just sold - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], -price) - dp[1] = max(dc[1], dc[0] + price) - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices) { - const dp = [-prices[0], 0] - - for (let i = 1; i < prices.length; i++) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], -prices[i]) - dp[1] = Math.max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], -prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/122-best-time-to-buy-and-sell-stock-ii.md b/en/1-1000/122-best-time-to-buy-and-sell-stock-ii.md deleted file mode 100644 index 3a490b7..0000000 --- a/en/1-1000/122-best-time-to-buy-and-sell-stock-ii.md +++ /dev/null @@ -1,135 +0,0 @@ -# 122. Best Time to Buy and Sell Stock II (Dynamic Programming Solution) -LeetCode link: [122. Best Time to Buy and Sell Stock II](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) - -## LeetCode problem description -You are given an integer array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -On each day, you may decide to buy and/or sell the stock. You can only hold **at most one** share of the stock at any time. However, you can buy it then immediately sell it **on the same day**. - -Find and return the **maximum** profit you can achieve. - -``` ------------------------------------------------------------------------------------------------------------------------ -[Example 1] - -Input: prices = [7,1,5,3,6,4] -Output: 7 - -Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. -Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. -Total profit is 4 + 3 = 7. ------------------------------------------------------------------------------------------------------------------------ -[Example 2] - -Input: prices = [1,2,3,4,5] -Output: 4 - -Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. -Total profit is 4. ------------------------------------------------------------------------------------------------------------------------ -[Example 3] - -Input: prices = [7,6,4,3,1] -Output: 0 - -Explanation: There is no way to make a positive profit, so we never buy the stock to achieve the maximum profit of 0. ------------------------------------------------------------------------------------------------------------------------ -[Constraints] - -1 <= prices.length <= 3 * 10000 -0 <= prices[i] <= 10000 ------------------------------------------------------------------------------------------------------------------------ -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - # states: - # 0: hold stock - # 1) keep holding - # 2) today just bought - # 1: no stock - # 1) keep no stock - # 2) today just sold - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], dc[1] - price) - dp[1] = max(dc[1], dc[0] + price) - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices) { - const dp = [-prices[0], 0] - - for (let i = 1; i < prices.length; i++) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], dc[1] - prices[i]) - dp[1] = Math.max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], dc[1] - prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/123-best-time-to-buy-and-sell-stock-iii.md b/en/1-1000/123-best-time-to-buy-and-sell-stock-iii.md deleted file mode 100644 index 111f681..0000000 --- a/en/1-1000/123-best-time-to-buy-and-sell-stock-iii.md +++ /dev/null @@ -1,133 +0,0 @@ -# 123. Best Time to Buy and Sell Stock III (Dynamic Programming Solution) -LeetCode link: [122. Best Time to Buy and Sell Stock III](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -Find the **maximum** profit you can achieve. You may complete **at most two transactions**. - -**Note**: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). - -``` ------------------------------------------------------------------------------------------------------------------------ -[Example 1] - -Input: prices = [3,3,5,0,0,3,1,4] -Output: 6 - -Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3. -Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3. ------------------------------------------------------------------------------------------------------------------------ -[Example 2] - -Input: prices = [1,2,3,4,5] -Output: 4 - -Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. -Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again. ------------------------------------------------------------------------------------------------------------------------ -[Example 3] - -Input: prices = [7,6,4,3,1] -Output: 0 - -Explanation: In this case, no transaction is done, i.e. max profit = 0. ------------------------------------------------------------------------------------------------------------------------ -[Constraints] - -1 <= prices.length <= 100000 -0 <= prices[i] <= 100000 ------------------------------------------------------------------------------------------------------------------------ -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - dp = [-prices[0], 0, -prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], -price) - dp[1] = max(dc[1], dc[0] + price) - dp[2] = max(dc[2], dc[1] - price) - dp[3] = max(dc[3], dc[2] + price) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices) { - const dp = [-prices[0], 0, -prices[0], 0] - - for (const price of prices.slice(1,)) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], -price) - dp[1] = Math.max(dc[1], dc[0] + price) - dp[2] = Math.max(dc[2], dc[1] - price) - dp[3] = Math.max(dc[3], dc[2] + price) - } - - return dp[3] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0, -prices[0], 0} - - for _, price := range prices[1:] { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], -price) - dp[1] = max(dc[1], dc[0] + price) - dp[2] = max(dc[2], dc[1] - price) - dp[3] = max(dc[3], dc[2] + price) - } - - return dp[3] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/127-word-ladder.md b/en/1-1000/127-word-ladder.md deleted file mode 100644 index b1bc0b8..0000000 --- a/en/1-1000/127-word-ladder.md +++ /dev/null @@ -1,164 +0,0 @@ -# LeetCode 127. Word Ladder's Solution -LeetCode link: [127. Word Ladder](https://leetcode.com/problems/word-ladder/) - -## LeetCode problem description -A **transformation sequence** from word `beginWord` to word `endWord` using a dictionary `wordList` is a sequence of words `beginWord -> s1 -> s2 -> ... -> sk` such that: - -* Every adjacent pair of words differs by a single letter. -* Every `si` for `1 <= i <= k` is in `wordList`. Note that `beginWord` does not need to be in `wordList`. -* `sk == endWord` - -Given two words, `beginWord` and `endWord`, and a dictionary `wordList`, return **the number of words** in the **shortest transformation sequence** from `beginWord` to `endWord`, or `0` if no such sequence exists. - -### Example 1 -``` -Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] -Output: 5 -Explanation: One shortest transformation sequence is "hit" -> "hot" -> "dot" -> "dog" -> cog", which is 5 words long. -``` - -### Example 2 -``` -Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"] -Output: 0 -Explanation: The endWord "cog" is not in wordList, therefore there is no valid transformation sequence. -``` - -### Constraints -- `1 <= beginWord.length <= 10` -- `endWord.length == beginWord.length` -- `1 <= wordList.length <= 5000` -- `wordList[i].length == beginWord.length` -- `beginWord`, `endWord`, and `wordList[i]` consist of lowercase English letters. -- `beginWord != endWord` -- All the words in `wordList` are **unique**. - -## Intuition -This problem is hard. Before solving this problem, you can do the following problem first: - -- [200. Number of Islands (Solution 3: Breadth-First Search)](200-number-of-islands-3.md) - -The **word transformation sequence** problem can be abstracted into a **graph theory** problem. And it is an **undirected graph**: - -![](../../images/127.png) - -### Breadth-First Search -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **Breadth-First Search** can be thought of as visiting vertices in rounds and rounds. Actually, whenever you see a question is about - getting `minimum number` of something of a graph, `Breadth-First Search` would probably help. - -* `Breadth-First Search` emphasizes first-in-first-out, so a **queue** is needed. - -## Approach -1. `Breadth-First Search` a graph means traversing **from near to far**, from `circle 1` to `circle N`. Each `circle` is a round of iteration. -1. So through `Breadth-First Search`, when a word matches `endWord`, the game is over, and we can return the number of **circle** as a result. - -## Complexity -* Time: `O((26 * end_word.length) * N)`. -* Space: `O(N)`. - -## Python -```python -from collections import deque - -class Solution: - def ladderLength(self, begin_word: str, end_word: str, word_list: List[str]) -> int: - words = set(word_list) - - if end_word not in words: - return 0 - - if begin_word == end_word: - return 1 - - queue = deque([begin_word]) - - if begin_word in words: - words.remove(begin_word) - - result = 0 - - while queue: - size = len(queue) - result += 1 - - for i in range(size): - current_word = queue.popleft() - - for word in one_letter_changed_words(current_word): - if word == end_word: - return result + 1 - - if word in words: - queue.append(word) - words.remove(word) - - return 0 - - -def one_letter_changed_words(word): - words = [] - - for i in range(len(word)): - for letter in 'abcdefghijklmnopqrstuvwxyz': - if letter != word[i]: - words.append(word[:i] + letter + word[i + 1:]) - - return words -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/139-word-break.md b/en/1-1000/139-word-break.md deleted file mode 100644 index 9f17e96..0000000 --- a/en/1-1000/139-word-break.md +++ /dev/null @@ -1,210 +0,0 @@ -# 139. Word Break -LeetCode link: [139. Word Break](https://leetcode.com/problems/word-break/) - -## LeetCode problem description -> Given a string `s` and a dictionary of strings `wordDict`, return `true` if `s` can be segmented into a space-separated sequence of one or more dictionary words. - -Note that the same word in the dictionary may be **reused multiple times** in the segmentation. - -``` ---------------------------------------------------------------------------------------------- -[Example 1] - -Input: s = "leetcode", wordDict = ["leet","code"] -Output: true -Explanation: Return true because "leetcode" can be segmented as "leet code". ---------------------------------------------------------------------------------------------- -[Example 2] - -Input: s = "applepenapple", wordDict = ["apple","pen"] -Output: true -Explanation: Return true because "applepenapple" can be segmented as "apple pen apple". - Note that you are allowed to reuse a dictionary word. ---------------------------------------------------------------------------------------------- -[Constraints] - -1 <= s.length <= 300 -1 <= wordDict.length <= 1000 -1 <= wordDict[i].length <= 20 -'s' and 'wordDict[i]' consist of only lowercase English letters. -All the strings of 'wordDict' are unique. ---------------------------------------------------------------------------------------------- -``` - -## Thoughts -This is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public bool WordBreak(string s, IList wordDict) - { - var dp = new bool[s.Length + 1]; - dp[0] = true; - - for (var i = 1; i < dp.Length; i++) - { - foreach (var word in wordDict) - { - if (dp[i]) - { - break; - } - - if (i >= word.Length) - { - dp[i] = dp[i - word.Length] && word == s[(i - word.Length)..i]; - } - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def wordBreak(self, s: str, wordDict: List[str]) -> bool: - dp = [False] * (len(s) + 1) - dp[0] = True - - for i in range(1, len(dp)): - for word in wordDict: - if dp[i]: - break - - if i >= len(word): - dp[i] = dp[i - len(word)] and word == s[i - len(word):i] - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - bool wordBreak(string s, vector& wordDict) { - auto dp = vector(s.size() + 1); - dp[0] = true; - - for (auto i = 1; i < dp.size(); i++) { - for (auto word : wordDict) { - if (dp[i]) { - break; - } - if (i >= word.size()) { - dp[i] = dp[i - word.size()] && - word == s.substr(i - word.size(), word.size()); - } - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public boolean wordBreak(String s, List wordDict) { - var dp = new boolean[s.length() + 1]; - dp[0] = true; - - for (var i = 1; i < dp.length; i++) { - for (var word : wordDict) { - if (dp[i]) { - break; - } - if (i >= word.length()) { - dp[i] = dp[i - word.length()] && - word.equals(s.substring(i - word.length(), i)); - } - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -``` -var wordBreak = function (s, wordDict) { - const dp = Array(s.length + 1).fill(false) - dp[0] = true - - for (let i = 1; i < dp.length; i++) { - for (const word of wordDict) { - if (dp[i]) { - break - } - if (i >= word.length) { - dp[i] = dp[i - word.length] && word == s.slice(i - word.length, i) - } - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func wordBreak(s string, wordDict []string) bool { - dp := make([]bool, len(s) + 1) - dp[0] = true - - for i := 1; i < len(dp); i++ { - for _, word := range wordDict { - if dp[i] { - break - } - if i >= len(word) { - dp[i] = dp[i - len(word)] && word == s[i - len(word):i] - } - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def word_break(s, word_dict) - dp = Array.new(s.size + 1, false) - dp[0] = true - - (1...dp.size).each do |i| - word_dict.each do |word| - break if dp[i] - - if i >= word.size - dp[i] = dp[i - word.size] && word == s[(i - word.size)...i] - end - end - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/144-binary-tree-preorder-traversal.md b/en/1-1000/144-binary-tree-preorder-traversal.md deleted file mode 100644 index 847855d..0000000 --- a/en/1-1000/144-binary-tree-preorder-traversal.md +++ /dev/null @@ -1,139 +0,0 @@ -# 144. Binary Tree Preorder Traversal - Best Practices of LeetCode Solutions -LeetCode link: [144. Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal), difficulty: **Easy**. - -## LeetCode description of "144. Binary Tree Preorder Traversal" -Given the `root` of a binary tree, return _the preorder traversal of its nodes' values_. - -### [Example 1] - -**Input**: `root = [1,null,2,3]` - -**Output**: `[1,2,3]` - -**Explanation**: - -![](../../images/examples/144_1.png) - -### [Example 2] - -**Input**: `root = [1,2,3,4,5,null,8,null,null,6,7,9]` - -**Output**: `[1,2,4,5,6,7,3,8,9]` - -**Explanation**: - -![](../../images/examples/144_2.png) - -### [Example 3] - -**Input**: `root = []` - -**Output**: `[]` - -### [Example 4] - -**Input**: `root = [1]` - -**Output**: `[1]` - -### [Constraints] -- The number of nodes in the tree is in the range `[0, 100]`. -- `-100 <= Node.val <= 100` - -## Intuition -Will be added later. - -## Steps -Will be added later. - -## Complexity -Recursive solution and iterative solution are equal in complexity. - -* Time: `O(N)`. -* Space: `O(N)`. - -## Follow-up -Recursive solution is trivial, could you do it iteratively? - -## Follow-up intuition -Will be added later. - -## Python -### Solution 1: Recursion -```python -class Solution: - def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: - self.values = [] - - self.traverse(root) - - return self.values - - def traverse(self, node): - if node is None: - return - - self.values.append(node.val) - - self.traverse(node.left) - - self.traverse(node.right) -``` - -### Solution 2: Iteration -```python -class Solution: - def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: - values = [] - stack = [] - - if root: - stack.append(root) - - while stack: - node = stack.pop() - values.append(node.val) - - if node.right: - stack.append(node.right) - - if node.left: - stack.append(node.left) - - return values -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/15-3sum.md b/en/1-1000/15-3sum.md deleted file mode 100644 index dee8b75..0000000 --- a/en/1-1000/15-3sum.md +++ /dev/null @@ -1,515 +0,0 @@ -# 15. 3Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [15. 3Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/15-3sum) for a better experience! - -LeetCode link: [15. 3Sum](https://leetcode.com/problems/3sum), difficulty: **Medium**. - -## LeetCode description of "15. 3Sum" - -Given an integer array nums, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j`, `i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`. - -Notice that the solution set must not contain duplicate triplets. - -### [Example 1] - -**Input**: `nums = [-1,0,1,2,-1,-4]` - -**Output**: `[[-1,-1,2],[-1,0,1]]` - -**Explanation**: - -

nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
-nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
-nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
-The distinct triplets are [-1,0,1] and [-1,-1,2].
-Notice that the order of the output and the order of the triplets does not matter.

- - -### [Example 2] - -**Input**: `nums = [0,1,1]` - -**Output**: `[]` - -**Explanation**: - -

The only possible triplet does not sum up to 0.

- - -### [Example 3] - -**Input**: `nums = [0,0,0]` - -**Output**: `[[0,0,0]]` - -**Explanation**: `The only possible triplet sums up to 0.` - -### [Constraints] - -- `3 <= nums.length <= 3000` -- `-10^5 <= nums[i] <= 10^5` - -### [Hints] - -
- Hint 1 - So, we essentially need to find three numbers `x`, `y`, and `z` such that they add up to the given value. If we fix one of the numbers say `x`, we are left with the two-sum problem at hand! - - -
- -
- Hint 2 - For the two-sum problem, if we fix one of the numbers, say `x`, we have to scan the entire array to find the next number `y`, which is `value - x` where value is the input parameter. Can we change our array somehow so that this search becomes faster? - - -
- -
- Hint 3 - The second train of thought for two-sum is, without changing the array, can we use additional space somehow? Like maybe a hash map to speed up the search? - - -
- -## Intuition 1 - -1. The `sum` of three numbers equals `0`, which is equivalent to the `sum` of *two numbers* equaling the ***negative*** third number. -2. There are two options: - - Option 1. First `determine one number`, and then `find the other two numbers`. - - Option 2. First `determine two numbers`, and then `find the third number`. -3. If you choose `option 2`, you need to use `Map`. Because you need to deduplicate `nums`; when searching for the third number in `Map`, you also need to avoid the two numbers that have been determined, which is more troublesome to implement. -4. If you choose `option 1`, you need to use the `two pointers` algorithm when searching for the other two numbers. -5. For `option 2`, only the `Python` sample code is given. This article focuses on `option 1`. - -## Step by Step Solutions - -1. Sort `nums`. -2. Iterate over `nums`. -3. pseudocode: - - ```javascript - for (i = 0; i < nums.length; i++) { - left = i + 1 - right = nums.length - 1 - - while (left < right) { - if (condition1) { - left += 1 - } else (condition2) { - right -= 1 - } - } - } - ``` - -## Complexity - -- Time complexity: `O(N * N)`. -- Space complexity: `O(N)`. - -## Python - -```python -# If you want the program to run faster, uncomment the two places in the code. -class Solution: - def threeSum(self, nums: List[int]) -> List[List[int]]: - nums.sort() - # nums_2 = [] - # for i, num in enumerate(nums): - # if i >= 3 and num == nums[i - 1] == nums[i - 2] == nums[i - 3]: - # continue - # nums_2.append(num) - # nums = nums_2 - results = set() - - for i, num in enumerate(nums[:len(nums) - 2]): - # if num > 0: - # break - left = i + 1 - right = len(nums) - 1 - - while left < right: - sum_ = nums[left] + nums[right] - if sum_ == -num: - results.add((num, nums[left], nums[right])) - left += 1 - elif sum_ > -num: - right -= 1 - else: - left += 1 - - return list(results) -``` - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer[][]} -def three_sum(nums) - nums.sort! - results = Set.new - - nums_2 = [] - nums.each_with_index do |num, i| - next if i >= 3 && num == nums[i - 1] && num == nums[i - 2] && num == nums[i - 3] - nums_2.append(num) - end - - nums = nums_2 - - # Iterate through each number as potential first element - (0...nums.length - 2).each do |i| - break if nums[i] > 0 - - left = i + 1 - right = nums.length - 1 - - # Two-pointer approach for remaining elements - while left < right - current_sum = nums[i] + nums[left] + nums[right] - if current_sum == 0 - # Add sorted triplet to avoid duplicates - results.add([nums[i], nums[left], nums[right]]) - left += 1 - right -= 1 - elsif current_sum < 0 - left += 1 # Need larger sum - else - right -= 1 # Need smaller sum - end - end - end - - results.to_a -end -``` - -## Go - -```go -func threeSum(nums []int) [][]int { - sort.Ints(nums) - - nums2 := make([]int, 0) - for i, num := range nums { - if i >= 3 && num == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] { - continue - } - nums2 = append(nums2, num) - } - - nums = nums2 - results := make([][]int, 0) - seen := make(map[string]bool) - - for i := 0; i < len(nums)-2; i++ { - // if nums[i] > 0 { - // break - // } - - left := i + 1 - right := len(nums) - 1 - - for left < right { - sum := nums[left] + nums[right] - if sum == -nums[i] { - triplet := []int{nums[i], nums[left], nums[right]} - key := fmt.Sprintf("%d,%d,%d", triplet[0], triplet[1], triplet[2]) - if !seen[key] { - results = append(results, triplet) - seen[key] = true - } - left++ - } else if sum > -nums[i] { - right-- - } else { - left++ - } - } - } - - return results -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> threeSum(vector& nums) { - sort(nums.begin(), nums.end()); - - // Uncomment to speed up - // vector nums2; - // for (int i = 0; i < nums.size(); i++) { - // if (i >= 3 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && - // nums[i-2] == nums[i-3]) { - // continue; - // } - // nums2.push_back(nums[i]); - // } - // nums = nums2; - - vector> results; - set> seen; - - for (int i = 0; i < nums.size() - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - int left = i + 1; - int right = nums.size() - 1; - - while (left < right) { - int sum = nums[left] + nums[right]; - - if (sum == -nums[i]) { - vector triplet = {nums[i], nums[left], nums[right]}; - - if (seen.find(triplet) == seen.end()) { - results.push_back(triplet); - seen.insert(triplet); - } - - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number[][]} - */ -var threeSum = function(nums) { - nums.sort((a, b) => a - b); - - // Uncomment to speed up - // let nums2 = []; - // for (let i = 0; i < nums.length; i++) { - // if (i >= 3 && nums[i] === nums[i-1] && nums[i-1] === nums[i-2] && nums[i-2] === nums[i-3]) { - // continue; - // } - // nums2.push(nums[i]); - // } - // nums = nums2; - - const results = []; - const seen = new Set(); - - for (let i = 0; i < nums.length - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - let left = i + 1; - let right = nums.length - 1; - - while (left < right) { - const sum = nums[left] + nums[right]; - - if (sum === -nums[i]) { - const triplet = [nums[i], nums[left], nums[right]]; - const key = triplet.join(','); - if (!seen.has(key)) { - results.push(triplet); - seen.add(key); - } - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; -}; -``` - -## C# - -```csharp -public class Solution { - public IList> ThreeSum(int[] nums) { - Array.Sort(nums); - - // Uncomment to speed up - // var nums2 = new List(); - // for (int i = 0; i < nums.Length; i++) { - // if (i >= 3 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3]) { - // continue; - // } - // nums2.Add(nums[i]); - // } - // nums = nums2.ToArray(); - - var results = new List>(); - var seen = new HashSet(); - - for (int i = 0; i < nums.Length - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - int left = i + 1; - int right = nums.Length - 1; - - while (left < right) { - int sum = nums[left] + nums[right]; - if (sum == -nums[i]) { - var triplet = new List { nums[i], nums[left], nums[right] }; - string key = string.Join(",", triplet); - if (!seen.Contains(key)) { - results.Add(triplet); - seen.Add(key); - } - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; - } -} -``` - -## Java - -```java -class Solution { - public List> threeSum(int[] nums) { - Arrays.sort(nums); - - // Uncomment to speed up - // List nums2 = new ArrayList<>(); - // for (int i = 0; i < nums.length; i++) { - // if (i >= 3 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3]) { - // continue; - // } - // nums2.add(nums[i]); - // } - // nums = nums2.stream().mapToInt(i -> i).toArray(); - - List> results = new ArrayList<>(); - var seen = new HashSet<>(); - - for (int i = 0; i < nums.length - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - int left = i + 1; - int right = nums.length - 1; - - while (left < right) { - int sum = nums[left] + nums[right]; - if (sum == -nums[i]) { - List triplet = Arrays.asList(nums[i], nums[left], nums[right]); - if (!seen.contains(triplet)) { - results.add(triplet); - seen.add(triplet); - } - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -Please refer to the idea of `​​​​Solution 1`. Here we only give the code to explain why using `Map` is not a good idea. - -## Complexity - -- Time complexity: `O(N * N)`. -- Space complexity: `O(N)`. - -## Python - -```python -# from collections import defaultdict - -class Solution: - def threeSum(self, nums: List[int]) -> List[List[int]]: - nums = duplicate_removed_nums(nums) - - results = set() - num_to_indices = defaultdict(list) - - for i, num in enumerate(nums): - num_to_indices[num].append(i) - - for i in range(len(nums) - 1): - for j in range(i + 1, len(nums)): - if -(nums[i] + nums[j]) in num_to_indices: - for index in num_to_indices[-(nums[i] + nums[j])]: - if index not in (i, j): - result = [nums[i], nums[j], nums[index]] - result.sort() - results.add(tuple(result)) - - return list(results) - - -def duplicate_removed_nums(nums): - num_to_count = defaultdict(int) - - for i, num in enumerate(nums): - if num_to_count[num] <= 2 or (num_to_count[num] <= 3 and num == 0): - num_to_count[num] += 1 - - new_nums = [] - - for num in num_to_count: - new_nums.extend([num] * num_to_count[num]) - - return new_nums -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [15. 3Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/15-3sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/151-reverse-words-in-a-string.md b/en/1-1000/151-reverse-words-in-a-string.md deleted file mode 100644 index fe73121..0000000 --- a/en/1-1000/151-reverse-words-in-a-string.md +++ /dev/null @@ -1,189 +0,0 @@ -# 151. Reverse Words in a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [151. Reverse Words in a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/151-reverse-words-in-a-string) for a better experience! - -LeetCode link: [151. Reverse Words in a String](https://leetcode.com/problems/reverse-words-in-a-string), difficulty: **Medium**. - -## LeetCode description of "151. Reverse Words in a String" - -Given an input string `s`, reverse the order of the **words**. - -A **word** is defined as a sequence of non-space characters. The **words** in `s` will be separated by at least one space. - -Return *a string of the words in reverse order concatenated by a single space*. - -**Note** that `s` may contain leading or trailing spaces or multiple spaces between two words. The returned string should only have a single space separating the words. Do not include any extra spaces. - -### [Example 1] - -**Input**: `s = "the sky is blue"` - -**Output**: `"blue is sky the"` - -### [Example 2] - -**Input**: `s = " hello world "` - -**Output**: `"world hello"` - -### [Example 3] - -**Input**: `"a good example"` - -**Output**: `"example good a"` - -### [Constraints] - -- `1 <= s.length <= 10^4` -- `s` contains English letters (upper-case and lower-case), digits, and spaces `' '`. -- There is **at least one** word in `s`. - -**Follow-up**: If the string data type is mutable in your language, can you solve it **in-place** with `O(1)` extra space? - - - -## Intuition - -1. Split the string into an array of words (need to remove empty strings) -2. Reverse the order of the words -3. Join the words with a single space - -## Step by Step Solutions - -1. Split the string using `split(' ')` -2. Remove empty strings -3. Reverse the word array using `reverse` -4. Merge into the final string using `join(' ')` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def reverseWords(self, s: str) -> str: - words = [word for word in s.split(' ') if word] - return ' '.join(words[::-1]) -``` - -## Java - -```java -class Solution { - public String reverseWords(String s) { - var wordList = new ArrayList(); - var words = s.split(" "); - - for (var word : words) { - if (!word.isEmpty()) { - wordList.add(word); - } - } - - int left = 0; - int right = wordList.size() - 1; - while (left < right) { - Collections.swap(wordList, left, right); - left++; - right--; - } - - return String.join(" ", wordList); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string reverseWords(string s) { - istringstream iss(s); - string word; - vector word_list; - - // 1. Extract words from the string. - // The istringstream >> operator automatically handles - // multiple spaces between words and leading/trailing spaces. - while (iss >> word) { - word_list.push_back(word); - } - - reverse(word_list.begin(), word_list.end()); - - // 2. Join the words with a single space. - string result = ""; - result = word_list[0]; - for (auto i = 1; i < word_list.size(); ++i) { - result += " "; - result += word_list[i]; - } - - return result; - } -}; - -``` - -## JavaScript - -```javascript -var reverseWords = function(s) { - const words = s.split(' ').filter((word) => word !== ''); - return words.reverse().join(' '); -}; -``` - -## Go - -```go -func reverseWords(s string) string { - words := strings.Fields(s) // Fields splits on whitespace and ignores multiple spaces - - // Reverse the words - for i, j := 0, len(words) - 1; i < j; { - words[i], words[j] = words[j], words[i] - i += 1 - j -= 1 - } - - return strings.Join(words, " ") -} -``` - -## C# - -```csharp -public class Solution { - public string ReverseWords(string s) { - // Split into words, remove empty entries, reverse - var words = s.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries).Reverse(); - return string.Join(" ", words); - } -} -``` - -## Ruby - -```ruby -def reverse_words(s) - s.split(' ').reject(&:empty?).reverse.join(' ') -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [151. Reverse Words in a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/151-reverse-words-in-a-string). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/160-intersection-of-two-linked-lists.md b/en/1-1000/160-intersection-of-two-linked-lists.md deleted file mode 100644 index 4c45651..0000000 --- a/en/1-1000/160-intersection-of-two-linked-lists.md +++ /dev/null @@ -1,501 +0,0 @@ -# 160. Intersection of Two Linked Lists - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [160. Intersection of Two Linked Lists - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/160-intersection-of-two-linked-lists) for a better experience! - -LeetCode link: [160. Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists), difficulty: **Easy**. - -## LeetCode description of "160. Intersection of Two Linked Lists" - -Given the heads of two singly linked-lists `headA` and `headB`, return _the node at which the two lists intersect_. If the two linked lists have no intersection at all, return `null`. - -For example, the following two linked lists begin to intersect at node `c1`: - -![](../../images/examples/160.png) - -The test cases are generated such that there are **no cycles** anywhere in the entire linked structure. - -**Note** that the linked lists must **retain their original structure** after the function returns. - -### [Example 1] - -![](../../images/examples/160_1.png) - -**Input**: `listA = [4,1,8,4,5], listB = [5,6,1,8,4,5]` - -**Output**: `Intersected at '8'` - -### [Example 2] - -![](../../images/examples/160_2.png) - -**Input**: `intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4]` - -**Output**: `Intersected at '2'` - -### [Example 3] - -![](../../images/examples/160_3.png) - -**Input**: `listA = [2,6,4], listB = [1,5]` - -**Output**: `No intersection` - -### [Constraints] - -- The number of nodes of `listA` is in the `m`. -- The number of nodes of `listB` is in the `n`. -- `1 <= m, n <= 3 * 10^4` -- `1 <= Node.val <= 10^5` - -
-**Follow up**: Could you write a solution that runs in `O(m + n)` time and use only `O(1)` memory? - -## Intuition - -This is a typical "encounter" problem, and it is best to transform it into a real-life scenario to enhance understanding. - -Suppose you are A, and you are pursuing B. The destination is school. On the way to school, the distance at the back is what you both have to go through, and the distance at the front is for each of you to go your own way. The node spacing is assumed to be one kilometer. - -Now, one morning, you both finished breakfast at the same time and are going to ride your bike to school. And you have a goal: to meet B and chat with him/her for a few words. What will you do? (Take Example 1 as an example) - -
Click to view the answer

-You must first calculate how many kilometers her home is farther from the school than your home, and then wait for her to walk these kilometers before setting off. As long as you have the same speed, you will definitely meet, and the node where you meet is the answer. - -1. First calculate the number of nodes in the two linked lists A and B. The number of nodes in linked list A is `node_count_a`, and the number of nodes in linked list B is `node_count_b`. -2. If `node_count_b > node_count_a`, then perform `node = node.next` for `node_count_b - node_count_a` times on linked list B. -3. At this time, repeat `node = node.next` on the two linked lists until the same node is found or one of the linked lists has reached the end. -

- -## Step by Step Solutions - -1. First calculate the number of nodes in the two linked lists A and B. The number of nodes in linked list A is `node_count_a`, and the number of nodes in linked list B is `node_count_b`. - - ```python - node_count_a = 0 - node_count_b = 0 - - node = headA - while node: - node_count_a += 1 - node = node.next - ``` - -2. If `node_count_b > node_count_a`, then perform `node = node.next` for `node_count_b - node_count_a` times on linked list B. - - ```python - bigger = headA - smaller = headB - - if node_count_b > node_count_a: - bigger = headB - smaller = headA - - for _ in range(abs(node_count_b - node_count_a)): - bigger = bigger.next - ``` - -3. At this time, repeat `node = node.next` on the two linked lists until the same node is found or one of the linked lists has reached the end. - - ```python - while bigger and smaller: - if bigger == smaller: - return bigger - - bigger = bigger.next - smaller = smaller.next - - return None - ``` - -## Complexity - -- Time complexity: `O(m + n)`. -- Space complexity: `O(1)`. - -## Java - -```java -/** - * public class ListNode { - * int val; - * ListNode next; - * ListNode(int x) { - * val = x; - * next = null; - * } - * } - */ -public class Solution { - public ListNode getIntersectionNode(ListNode headA, ListNode headB) { - var nodeCountA = 0; - var nodeCountB = 0; - - var node = headA; - while (node != null) { - nodeCountA += 1; - node = node.next; - } - - node = headB; - while (node != null) { - nodeCountB += 1; - node = node.next; - } - - var bigger = headA; - var smaller = headB; - - if (nodeCountB > nodeCountA) { - bigger = headB; - smaller = headA; - } - - for (var i = 0; i < Math.abs(nodeCountB - nodeCountA); i++) { - bigger = bigger.next; - } - - while (bigger != null && smaller != null) { - if (bigger == smaller) { - return bigger; - } - - bigger = bigger.next; - smaller = smaller.next; - } - - return null; - } -} -``` - -## Python - -```python -# class ListNode: -# def __init__(self, x): -# self.val = x -# self.next = None - -class Solution: - def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: - node_count_a = 0 - node_count_b = 0 - - node = headA - while node: - node_count_a += 1 - node = node.next - - node = headB - while node: - node_count_b += 1 - node = node.next - - bigger = headA - smaller = headB - - if node_count_b > node_count_a: - bigger = headB - smaller = headA - - for _ in range(abs(node_count_b - node_count_a)): - bigger = bigger.next - - while bigger and smaller: - if bigger == smaller: - return bigger - - bigger = bigger.next - smaller = smaller.next - - return None -``` - -## JavaScript - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ -var getIntersectionNode = function (headA, headB) { - let nodeCountA = 0 - let nodeCountB = 0 - - let node = headA; - while (node != null) { - nodeCountA += 1 - node = node.next - } - - node = headB - while (node != null) { - nodeCountB += 1 - node = node.next - } - - let bigger = headA - let smaller = headB - - if (nodeCountB > nodeCountA) { - bigger = headB - smaller = headA - } - - for (var i = 0; i < Math.abs(nodeCountB - nodeCountA); i++) { - bigger = bigger.next - } - - while (bigger != null && smaller != null) { - if (bigger == smaller) { - return bigger - } - - bigger = bigger.next - smaller = smaller.next - } - - return null -}; -``` - -## C# - -```csharp -/** - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int x) { val = x; } - * } - */ -public class Solution -{ - public ListNode GetIntersectionNode(ListNode headA, ListNode headB) - { - int nodeCountA = 0; - int nodeCountB = 0; - - var node = headA; - while (node != null) - { - nodeCountA += 1; - node = node.next; - } - - node = headB; - while (node != null) - { - nodeCountB += 1; - node = node.next; - } - - var bigger = headA; - var smaller = headB; - - if (nodeCountB > nodeCountA) - { - bigger = headB; - smaller = headA; - } - - for (int i = 0; i < Math.Abs(nodeCountB - nodeCountA); i++) - { - bigger = bigger.next; - } - - while (bigger != null && smaller != null) - { - if (bigger == smaller) - { - return bigger; - } - - bigger = bigger.next; - smaller = smaller.next; - } - - return null; - } -} -``` - -## Ruby - -```ruby -# Definition for singly-linked list. -# class ListNode -# attr_accessor :val, :next -# def initialize(val) -# @val = val -# @next = nil -# end -# end - -# @param {ListNode} head_a -# @param {ListNode} head_b -# @return {ListNode} -def getIntersectionNode(head_a, head_b) - node_count_a = 0 - node_count_b = 0 - - node = head_a - while node - node_count_a += 1 - node = node.next - end - - node = head_b - while node - node_count_b += 1 - node = node.next - end - - bigger = head_a - smaller = head_b - - if node_count_b > node_count_a - bigger = head_b - smaller = head_a - end - - (node_count_b - node_count_a).abs.times do - bigger = bigger.next - end - - while bigger && smaller - return bigger if bigger == smaller - - bigger = bigger.next - smaller = smaller.next - end - - nil -end -``` - -## C++ - -```cpp -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { -public: - ListNode *getIntersectionNode(ListNode *head_a, ListNode *head_b) { - int node_count_a = 0; - int node_count_b = 0; - - ListNode *node = head_a; - while (node) { - node_count_a += 1; - node = node->next; - } - - node = head_b; - while (node) { - node_count_b += 1; - node = node->next; - } - - ListNode *bigger = head_a; - ListNode *smaller = head_b; - - if (node_count_b > node_count_a) { - bigger = head_b; - smaller = head_a; - } - - for (int i = 0; i < abs(node_count_b - node_count_a); i++) { - bigger = bigger->next; - } - - while (bigger && smaller) { - if (bigger == smaller) { - return bigger; - } - - bigger = bigger->next; - smaller = smaller->next; - } - - return nullptr; - } -}; -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func getIntersectionNode(headA, headB *ListNode) *ListNode { - nodeCountA := 0 - nodeCountB := 0 - - node := headA - for node != nil { - nodeCountA++ - node = node.Next - } - - node = headB - for node != nil { - nodeCountB++ - node = node.Next - } - - bigger := headA - smaller := headB - - if nodeCountB > nodeCountA { - bigger = headB - smaller = headA - } - - difference := nodeCountB - nodeCountA - if difference < 0 { - difference = -difference - } - - for i := 0; i < difference; i++ { - bigger = bigger.Next - } - - for bigger != nil && smaller != nil { - if bigger == smaller { - return bigger - } - bigger = bigger.Next - smaller = smaller.Next - } - - return nil -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [160. Intersection of Two Linked Lists - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/160-intersection-of-two-linked-lists). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/18-4sum.md b/en/1-1000/18-4sum.md deleted file mode 100644 index cd3d4e9..0000000 --- a/en/1-1000/18-4sum.md +++ /dev/null @@ -1,378 +0,0 @@ -# 18. 4Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [18. 4Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/18-4sum) for a better experience! - -LeetCode link: [18. 4Sum](https://leetcode.com/problems/4sum), difficulty: **Medium**. - -## LeetCode description of "18. 4Sum" - -Given an array `nums` of `n` integers, return *an array of all the* ***unique*** *quadruplets* `[nums[a], nums[b], nums[c], nums[d]]` such that: - -- `0 <= a, b, c, d < n` -- `a`, `b`, `c`, and `d` are **distinct**. -- `nums[a] + nums[b] + nums[c] + nums[d] == target` -- You may return the answer in **any order**. - -### [Example 1] - -**Input**: `nums = [1,0,-1,0,-2,2], target = 0` - -**Output**: `[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]` - -### [Example 2] - -**Input**: `nums = [2,2,2,2,2], target = 8` - -**Output**: `[[2,2,2,2]]` - -### [Constraints] - -- `1 <= nums.length <= 200` -- `-10^9 <= nums[i] <= 10^9` -- `-10^9 <= target <= 10^9` - -## Intuition - -1. The idea of this question is the same as [15. 3Sum](15-3sum.md), please click the link to view. -2. The difference is that `three numbers` becomes `four numbers`, and processing `four numbers` only requires **one more nested loop**. -3. In addition, the `target` parameter is added, which needs to be brought in as a condition during calculation. -4. You may have already seen that no matter it is `two numbers`, `three numbers` or `four numbers`, the `Two Pointers Technique` can be used. - -## Complexity - -- Time complexity: `O(N^3)`. -- Space complexity: `O(N)`. - -## Python - -```python -# If you want the program to run faster, uncomment the two places in the code. -class Solution: - def fourSum(self, nums: List[int], target: int) -> List[List[int]]: - nums.sort() - # nums_2 = [] - # for i, num in enumerate(nums): - # if i >= 4 and num == nums[i - 1] == nums[i - 2] == nums[i - 3] == nums[i - 4]: - # continue - # nums_2.append(num) - # nums = nums_2 - results = set() - - for i in range(len(nums) - 3): - for j in range(i + 1, len(nums) - 2): - num = nums[i] + nums[j] - # if num > target / 2: - # break - left = j + 1 - right = len(nums) - 1 - - while left < right: - sum_ = nums[left] + nums[right] - - if sum_ == target - num: - results.add((nums[i], nums[j], nums[left], nums[right])) - left += 1 - elif sum_ > target - num: - right -= 1 - else: - left += 1 - - return list(results) -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @param {number} target - * @return {number[][]} - */ -var fourSum = function(nums, target) { - nums.sort((a, b) => a - b); - - // Uncomment to speed up - // let nums2 = []; - // for (let i = 0; i < nums.length; i++) { - // if (i >= 4 && nums[i] === nums[i-1] && nums[i-1] === nums[i-2] && nums[i-2] === nums[i-3] && nums[i-3] === nums[i-4]) { - // continue; - // } - // nums2.push(nums[i]); - // } - // nums = nums2; - - const results = new Set(); - - for (let i = 0; i < nums.length - 3; i++) { - for (let j = i + 1; j < nums.length - 2; j++) { - const num = nums[i] + nums[j]; - // Uncomment to speed up - // if (num > target / 2) { - // break; - // } - let left = j + 1; - let right = nums.length - 1; - - while (left < right) { - const sum = nums[left] + nums[right]; - - if (sum === target - num) { - results.add([nums[i], nums[j], nums[left], nums[right]].join(',')); - left++; - } else if (sum > target - num) { - right--; - } else { - left++; - } - } - } - } - - return Array.from(results).map(str => str.split(',').map(Number)); -}; -``` - -## Ruby - -```ruby -# @param {Integer[]} nums -# @param {Integer} target -# @return {Integer[][]} -def four_sum(nums, target) - nums.sort! - - # Uncomment to speed up - # nums2 = [] - # nums.each_with_index do |num, i| - # next if i >= 4 && num == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4] - # nums2 << num - # end - # nums = nums2 - - results = Set.new - - (0..nums.length-4).each do |i| - (i+1..nums.length-3).each do |j| - num = nums[i] + nums[j] - # Uncomment to speed up - # break if num > target / 2 - left = j + 1 - right = nums.length - 1 - - while left < right - sum = nums[left] + nums[right] - - if sum == target - num - results.add([nums[i], nums[j], nums[left], nums[right]]) - left += 1 - elsif sum > target - num - right -= 1 - else - left += 1 - end - end - end - end - - results.to_a -end -``` - -## Java - -```java -class Solution { - public List> fourSum(int[] nums, int target) { - List> results = new ArrayList<>(); - - Arrays.sort(nums); - Set> seen = new HashSet<>(); - - for (int i = 0; i < nums.length - 3; i++) { - for (int j = i + 1; j < nums.length - 2; j++) { - int left = j + 1; - int right = nums.length - 1; - - while (left < right) { - long sum = (long) nums[i] + nums[j] + nums[left] + nums[right]; - - if (sum == target) { - List quadruplet = Arrays.asList(nums[i], nums[j], nums[left], nums[right]); - if (!seen.contains(quadruplet)) { - results.add(quadruplet); - seen.add(quadruplet); - } - left++; - } else if (sum < target) { - left++; - } else { - right--; - } - } - } - } - - return results; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> fourSum(vector& nums, int target) { - vector> results; - - sort(nums.begin(), nums.end()); - set> seen; - - for (int i = 0; i < nums.size() - 3; i++) { - for (int j = i + 1; j < nums.size() - 2; j++) { - int left = j + 1; - int right = nums.size() - 1; - - while (left < right) { - long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right]; - - if (sum == target) { - vector quadruplet = {nums[i], nums[j], nums[left], nums[right]}; - if (seen.find(quadruplet) == seen.end()) { - results.push_back(quadruplet); - seen.insert(quadruplet); - } - left++; - } else if (sum < target) { - left++; - } else { - right--; - } - } - } - } - - return results; - } -}; -``` - -## Go - -```go -// If you want the program to run faster, uncomment the two places in the code. - -func fourSum(nums []int, target int) [][]int { - sort.Ints(nums) - - // nums2 := make([]int, 0) - // for i := 0; i < len(nums); i++ { - // if i >= 4 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4] { - // continue - // } - // nums2 = append(nums2, nums[i]) - // } - // nums = nums2 - - results := make([][]int, 0) - seen := make(map[string]bool) - - for i := 0; i < len(nums)-3; i++ { - for j := i + 1; j < len(nums)-2; j++ { - num := nums[i] + nums[j] - // if num > target/2 { - // break - // } - left := j + 1 - right := len(nums) - 1 - - for left < right { - sum := nums[left] + nums[right] - - if sum == target-num { - quadruplet := []int{nums[i], nums[j], nums[left], nums[right]} - key := fmt.Sprintf("%d,%d,%d,%d", quadruplet[0], quadruplet[1], quadruplet[2], quadruplet[3]) - if !seen[key] { - results = append(results, quadruplet) - seen[key] = true - } - left++ - } else if sum > target-num { - right-- - } else { - left++ - } - } - } - } - - return results -} -``` - -## C# - -```csharp -// If you want the program to run faster, uncomment the two places in the code. -public class Solution { - public IList> FourSum(int[] nums, int target) { - Array.Sort(nums); - - // List nums2 = new List(); - // for (int i = 0; i < nums.Length; i++) { - // if (i >= 4 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4]) { - // continue; - // } - // nums2.Add(nums[i]); - // } - // nums = nums2.ToArray(); - - var results = new List>(); - var seen = new HashSet(); - - for (int i = 0; i < nums.Length - 3; i++) { - for (int j = i + 1; j < nums.Length - 2; j++) { - long num = (long)nums[i] + nums[j]; - // if (num > target / 2) { - // break; - // } - int left = j + 1; - int right = nums.Length - 1; - - while (left < right) { - long sum = (long)nums[left] + nums[right]; - - if (sum == target - num) { - var quadruplet = new[] { nums[i], nums[j], nums[left], nums[right] }; - string key = string.Join(",", quadruplet); - if (!seen.Contains(key)) { - results.Add(quadruplet); - seen.Add(key); - } - left++; - } else if (sum > target - num) { - right--; - } else { - left++; - } - } - } - } - - return results; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [18. 4Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/18-4sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/188-best-time-to-buy-and-sell-stock-iv.md b/en/1-1000/188-best-time-to-buy-and-sell-stock-iv.md deleted file mode 100644 index 92de27c..0000000 --- a/en/1-1000/188-best-time-to-buy-and-sell-stock-iv.md +++ /dev/null @@ -1,135 +0,0 @@ -# 188. Best Time to Buy and Sell Stock IV -LeetCode link: [188. Best Time to Buy and Sell Stock IV](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) - -## LeetCode problem description -You are given an integer array `prices` where `prices[i]` is the price of a given stock on the `i-th` day, and an integer `k`. - -Find the maximum profit you can achieve. You may complete at most `k` transactions: i.e. you may buy at most `k` times and sell at most `k` times. - -**Note**: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). -``` -------------------------------------------------------------------------------------------------------- -[Example 1] - -Input: k = 2, prices = [2,4,1] -Output: 2 - -Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2. -------------------------------------------------------------------------------------------------------- -[Example 2] - -Input: k = 2, prices = [3,2,6,5,0,3] -Output: 7 - -Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4. - Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3. -------------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= k <= 100 -1 <= prices.length <= 1000 -0 <= prices[i] <= 1000 -------------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n * k)`. -* Space: `O(n * k)`. - -## Python -```python -class Solution: - def maxProfit(self, k: int, prices: List[int]) -> int: - dp = [] - for _ in range(k): - dp.extend([-prices[0], 0]) - - for price in prices[1:]: - dc = dp.copy() - - for i in range(0, 2 * k, 2): - dp[i] = max( - dc[i], - (0 if i == 0 else dc[i - 1]) - price - ) - dp[i + 1] = max(dc[i + 1], dc[i] + price) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (k, prices) { - const dp = Array(k).fill([-prices[0], 0]).flat() - - for (const price of prices.slice(1,)) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], -price) - - for (let i = 1; i < k * 2; i++) { - dp[i] = Math.max(dc[i], dc[i - 1] + (i % 2 === 1 ? price : -price)) - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func maxProfit(k int, prices []int) int { - dp := slices.Repeat([]int{-prices[0], 0}, k) - - for _, price := range prices[1:] { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], -price) - - for i := 1; i < k * 2; i++ { - addition := price - if i % 2 == 0 { - addition *= -1 - } - dp[i] = max(dc[i], dc[i - 1] + addition) - } - } - - return dp[2 * k - 1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/19-remove-nth-node-from-end-of-list.md b/en/1-1000/19-remove-nth-node-from-end-of-list.md deleted file mode 100644 index 97a9ee8..0000000 --- a/en/1-1000/19-remove-nth-node-from-end-of-list.md +++ /dev/null @@ -1,390 +0,0 @@ -# 19. Remove Nth Node From End of List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [19. Remove Nth Node From End of List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/19-remove-nth-node-from-end-of-list) for a better experience! - -LeetCode link: [19. Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list), difficulty: **Medium**. - -## LeetCode description of "19. Remove Nth Node From End of List" - -Given the `head` of a linked list, remove the *nth* node from the end of the list and return *its head*. - -### [Example 1] - -![](../../images/examples/19_1.jpg) - -**Input**: `head = [1,2,3,4,5], n = 2` - -**Output**: `[1,2,3,5]` - -### [Example 2] - -**Input**: `head = [1], n = 1` - -**Output**: `[]` - -### [Example 3] - -**Input**: `head = [1,2], n = 1` - -**Output**: `[1]` - -### [Constraints] - -- The number of nodes in the list is `sz`. -- `1 <= sz <= 30` -- `0 <= Node.val <= 100` -- `1 <= n <= sz` - -### [Hints] - -
- Hint 1 - Maintain two pointers and update one with a delay of n steps. - - -
- -## Intuition - -1. Deleting the *nth* to last node in the linked list is equivalent to deleting the (node_count - n)th node in the linked list. -2. First find out `node_count`. -3. When `index == node_count - n`, delete the node by `node.next = node.next.next`. -4. Since the deleted node may be `head`, a virtual node `dummy_node` is used to facilitate unified processing. - -## Step by Step Solutions - -1. First find out `node_count`. - - ```ruby - node_count = 0 - node = head - - while node - node_count += 1 - node = node.next - end - ``` - -2. When `index == node_count - N`, delete the node by `node.next = node.next.next`. - - ```ruby - index = 0 - node = head - - while node - if index == node_count - n - node.next = node.next.next - break - end - - index += 1 - node = node.next - end - ``` - -3. Since the deleted node may be `head`, a virtual node `dummy_node` is used to facilitate unified processing. - - ```ruby - dummy_head = ListNode.new # 1 - dummy_head.next = head # 2 - node = dummy_head # 3 - - # omitted code - - return dummy_head.next - ``` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ -class Solution { - public ListNode removeNthFromEnd(ListNode head, int n) { - var nodeCount = 0; - var node = head; - - while (node != null) { - nodeCount++; - node = node.next; - } - - var index = 0; - var dummyHead = new ListNode(0, head); - node = dummyHead; - - while (node != null) { - if (index == nodeCount - n) { - node.next = node.next.next; - break; - } - - index++; - node = node.next; - } - - return dummyHead.next; - } -} -``` - -## Python - -```python -# Definition for singly-linked list. -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: - node_count = 0 - node = head - - while node: - node_count += 1 - node = node.next - - index = 0 - dummy_head = ListNode(next=head) - node = dummy_head - - while node: - if index == node_count - n: - node.next = node.next.next - break - - index += 1 - node = node.next - - return dummy_head.next -``` - -## C++ - -```cpp -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* removeNthFromEnd(ListNode* head, int n) { - auto node_count = 0; - auto node = head; - - while (node != nullptr) { - node_count += 1; - node = node->next; - } - - auto index = 0; - auto dummy_head = new ListNode(0, head); - node = dummy_head; - - for (auto i = 0; i < node_count - n; i++) { - node = node->next; - } - - auto target_node = node->next; - node->next = node->next->next; - delete target_node; - - auto result = dummy_head->next; - delete dummy_head; - return result; - } -}; -``` - -## JavaScript - -```javascript -/** - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var removeNthFromEnd = function (head, n) { - let nodeCount = 0 - let node = head - - while (node != null) { - nodeCount++ - node = node.next - } - - let index = 0 - let dummyHead = new ListNode(0, head) - node = dummyHead - - while (node != null) { - if (index == nodeCount - n) { - node.next = node.next.next - break - } - - index++ - node = node.next - } - - return dummyHead.next -}; -``` - -## C# - -```csharp -/** - * Definition for singly-linked list. - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution -{ - public ListNode RemoveNthFromEnd(ListNode head, int n) - { - int nodeCount = 0; - var node = head; - - while (node != null) - { - nodeCount++; - node = node.next; - } - - int index = 0; - var dummyHead = new ListNode(0, head); - node = dummyHead; - - while (node != null) - { - if (index == nodeCount - n) - { - node.next = node.next.next; - break; - } - - index++; - node = node.next; - } - - return dummyHead.next; - } -} -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func removeNthFromEnd(head *ListNode, n int) *ListNode { - nodeCount := 0 - node := head - - for node != nil { - nodeCount++ - node = node.Next - } - - index := 0 - dummyHead := &ListNode{0, head} - node = dummyHead - - for node != nil { - if index == nodeCount - n { - node.Next = node.Next.Next - break - } - - index++ - node = node.Next - } - - return dummyHead.Next -} -``` - -## Ruby - -```ruby -# class ListNode -# attr_accessor :val, :next -# -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def remove_nth_from_end(head, n) - node_count = 0 - node = head - - while node - node_count += 1 - node = node.next - end - - index = 0 - dummy_head = ListNode.new(0, head) - node = dummy_head - - while node - if index == node_count - n - node.next = node.next.next - break - end - - index += 1 - node = node.next - end - - dummy_head.next -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [19. Remove Nth Node From End of List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/19-remove-nth-node-from-end-of-list). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/198-house-robber.md b/en/1-1000/198-house-robber.md deleted file mode 100644 index a2ff275..0000000 --- a/en/1-1000/198-house-robber.md +++ /dev/null @@ -1,204 +0,0 @@ -# 198. House Robber -LeetCode link: [198. House Robber](https://leetcode.com/problems/house-robber/) - -## LeetCode problem description -You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected, and **it will automatically contact the police if two adjacent houses were broken into on the same night**. - -Given an integer array `nums` representing the amount of money of each house, return the maximum amount of money you can rob tonight **without alerting the police**. -``` -------------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [1,2,3,1] -Output: 4 -Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). - Total amount you can rob = 1 + 3 = 4. -------------------------------------------------------------------------------------------------- -[Example 2] -Input: nums = [2,7,9,3,1] -Output: 12 -Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1). - Total amount you can rob = 2 + 9 + 1 = 12. -------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 100 -0 <= nums[i] <= 400 -------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int Rob(int[] nums) - { - if (nums.Length == 1) - return nums[0]; - - var dp = new int[nums.Length]; - dp[0] = nums[0]; - dp[1] = Math.Max(nums[0], nums[1]); - - for (var i = 2; i < dp.Length; i++) - { - dp[i] = Math.Max(dp[i - 1], dp[i - 2] + nums[i]); - } - - return dp.Last(); - } -} -``` - -## Python -### Solution 1 -```python -class Solution: - def rob(self, nums: List[int]) -> int: - if len(nums) == 1: - return nums[0] - - dp = [0] * len(nums) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i in range(2, len(dp)): - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - - return dp[-1] -``` - -## Solution 2: Using 'dp' which size is 2 -```python -class Solution: - def rob(self, nums: List[int]) -> int: - if len(nums) == 1: - return nums[0] - - dp = [nums[0], max(nums[0], nums[1])] - - for num in nums[2:]: - dc = dp.copy() - - dp[1] = max(dc[1], dc[0] + num) - dp[0] = dc[1] - - return max(dp) -``` - -## C++ -```cpp -class Solution { -public: - int rob(vector& nums) { - if (nums.size() == 1) { - return nums[0]; - } - - auto dp = vector(nums.size()); - dp[0] = nums[0]; - dp[1] = max(nums[0], nums[1]); - - for (auto i = 2; i < dp.size(); i++) { - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]); - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int rob(int[] nums) { - if (nums.length == 1) { - return nums[0]; - } - - var dp = new int[nums.length]; - dp[0] = nums[0]; - dp[1] = Math.max(nums[0], nums[1]); - - for (var i = 2; i < dp.length; i++) { - dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -```javascript -var rob = function (nums) { - if (nums.length === 1) { - return nums[0] - } - - const dp = Array(nums.length).fill(0) - dp[0] = nums[0] - dp[1] = Math.max(nums[0], nums[1]) - - for (let i = 2; i < dp.length; i++) { - dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp.at(-1) -}; -``` - -## Go -```go -func rob(nums []int) int { - if len(nums) == 1 { - return nums[0] - } - - dp := make([]int, len(nums)) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i := 2; i < len(dp); i++ { - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def rob(nums) - return nums[0] if nums.size == 1 - - dp = Array.new(nums.size, 0) - dp[0] = nums[0] - dp[1] = [ nums[0], nums[1] ].max - - (2...dp.size).each do |i| - dp[i] = [ dp[i - 1], dp[i - 2] + nums[i] ].max - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/20-valid-parentheses.md b/en/1-1000/20-valid-parentheses.md deleted file mode 100644 index cebb114..0000000 --- a/en/1-1000/20-valid-parentheses.md +++ /dev/null @@ -1,356 +0,0 @@ -# 20. Valid Parentheses - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [20. Valid Parentheses - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/20-valid-parentheses) for a better experience! - -LeetCode link: [20. Valid Parentheses](https://leetcode.com/problems/valid-parentheses), difficulty: **Easy**. - -## LeetCode description of "20. Valid Parentheses" - -Given a string `s` containing just the characters `(`, `)`, `{`, `}`, `[` and `]`, determine if the input string is valid. - -An input string is valid if: - -1. Open brackets must be closed by the same type of brackets. -2. Open brackets must be closed in the correct order. -3. Every close bracket has a corresponding open bracket of the same type. - -### [Example 1] - -**Input**: `s = "()"` - -**Output**: `true` - -### [Example 2] - -**Input**: `s = "()[]{}"` - -**Output**: `true` - -### [Example 3] - -**Input**: `s = "(]"` - -**Output**: `false` - -### [Example 4] - -**Input**: `s = "([])"` - -**Output**: `true` - -### [Constraints] - -- `1 <= s.length <= 10000` -- `s` consists of parentheses only `()[]{}`. - -### [Hints] - -
- Hint 1 - Use a stack of characters. - - -
- -
- Hint 2 - When you encounter an opening bracket, push it to the top of the stack. - - -
- -
- Hint 3 - When you encounter a closing bracket, check if the top of the stack was the opening for it. If yes, pop it from the stack. Otherwise, return false. - - -
- -## Intuition - -1. Bracket matching focuses on the `previous character` and the `current character`. There are two situations to consider: - 1. If the `current character` is a left bracket, there is no need to match it and it can be saved directly. - 2. If the `current character` is a right bracket, and the `previous character` and the `current character` are paired, both characters can disappear; otherwise, if the pairing fails, `false` is returned directly. -2. This scenario that focuses on the `previous character` and the `current character` is suitable for implementation with a `stack`. -3. The mapping relationship between left and right brackets can be saved in a `Map`. -4. Finally, if the stack is empty, it means that all pairings are successful and `true` is returned; otherwise, `false` is returned. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## JavaScript - -```javascript -/** - * @param {string} s - * @return {boolean} - */ -var isValid = function (s) { - const closeToOpen = new Map([ - [')', '('], - ['}', '{'], - [']', '['], - ]) - const stack = [] - - for (const char of s) { - if (!closeToOpen.has(char)) { - // is open bracket - stack.push(char) - continue - } - // is close bracket - - if (stack.length === 0) { - return false - } - - // stack top value doesn't match the expected value - if (stack.pop() != closeToOpen.get(char)) { - return false - } - } - - return stack.length === 0 -}; -``` - -## Python - -```python -class Solution: - def isValid(self, s: str) -> bool: - # Map closing brackets to their opening brackets - close_to_open = { - ')': '(', - '}': '{', - ']': '[', - } - stack = [] - - for char in s: - if char not in close_to_open: - # is open bracket - stack.append(char) - continue - # is close bracket - - if not stack: - return False - - # stack top value doesn't match the expected value - if stack.pop() != close_to_open[char]: - return False - - return not stack -``` - -## Java - -```java -class Solution { - public boolean isValid(String s) { - // Map closing brackets to their opening brackets - var closeToOpen = new HashMap(); - closeToOpen.put(')', '('); - closeToOpen.put('}', '{'); - closeToOpen.put(']', '['); - - var stack = new Stack(); - - for (char c : s.toCharArray()) { - if (!closeToOpen.containsKey(c)) { - // is open bracket - stack.push(c); - continue; - } - // is close bracket - - if (stack.isEmpty()) { - return false; - } - - // stack top value doesn't match the expected value - if (stack.pop() != closeToOpen.get(c)) { - return false; - } - } - - return stack.isEmpty(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool isValid(string s) { - // Map closing brackets to their opening brackets - unordered_map closeToOpen = { - {')', '('}, - {'}', '{'}, - {']', '['} - }; - - stack st; - - for (char c : s) { - if (closeToOpen.find(c) == closeToOpen.end()) { - // is open bracket - st.push(c); - continue; - } - // is close bracket - - if (st.empty()) { - return false; - } - - // stack top value doesn't match the expected value - if (st.top() != closeToOpen[c]) { - return false; - } - - st.pop(); - } - - return st.empty(); - } -}; -``` - -## C# - -```csharp -public class Solution -{ - public bool IsValid(string s) - { - // Map closing brackets to their opening brackets - var closeToOpen = new Dictionary() - { - {')', '('}, - {'}', '{'}, - {']', '['} - }; - - var stack = new Stack(); - - foreach (char c in s) { - if (!closeToOpen.ContainsKey(c)) - { - // is open bracket - stack.Push(c); - continue; - } - // is close bracket - - if (stack.Count == 0) - { - return false; - } - - // stack top value doesn't match the expected value - if (stack.Pop() != closeToOpen[c]) - { - return false; - } - } - - return stack.Count == 0; - } -} -``` - -## Go - -```go -func isValid(s string) bool { - // Map closing brackets to their opening brackets - closeToOpen := map[rune]rune{ - ')': '(', - '}': '{', - ']': '[', - } - - stack := []rune{} - - for _, char := range s { - if _, isClose := closeToOpen[char]; !isClose { - // is open bracket - stack = append(stack, char) - continue - } - // is close bracket - - if len(stack) == 0 { - return false - } - - lastChar := stack[len(stack) - 1] - - // stack top value doesn't match the expected value - if lastChar != closeToOpen[char] { - return false - } - - stack = stack[:len(stack) - 1] // pop operation - } - - return len(stack) == 0 -} -``` - -## Ruby - -```ruby -# @param {String} s -# @return {Boolean} -def is_valid(s) - # Map closing brackets to their opening brackets - close_to_open = { - ')' => '(', - '}' => '{', - ']' => '[' - } - - stack = [] - - s.each_char do |char| - if !close_to_open.key?(char) - # is open bracket - stack.push(char) - next - end - # is close bracket - - if stack.empty? - return false - end - - # stack top value doesn't match the expected value - if stack.pop != close_to_open[char] - return false - end - end - - stack.empty? -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [20. Valid Parentheses - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/20-valid-parentheses). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/200-number-of-islands-2.md b/en/1-1000/200-number-of-islands-2.md deleted file mode 100644 index 7b54515..0000000 --- a/en/1-1000/200-number-of-islands-2.md +++ /dev/null @@ -1,476 +0,0 @@ -# 200. Number of Islands (Solution 2: 'Depth-First Search' by Iteration) -LeetCode link: [200. Number of Islands](https://leetcode.com/problems/number-of-islands/) - -## LeetCode problem description -Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return the number of islands. - -An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - -### Example 1 -``` -Input: grid = [ - ["1","1","1","1","0"], - ["1","1","0","1","0"], - ["1","1","0","0","0"], - ["0","0","0","0","0"] -] -Output: 1 -``` - -### Example 2 -``` -Input: grid = [ - ["1","1","0","0","0"], - ["1","1","0","0","0"], - ["0","0","1","0","0"], - ["0","0","0","1","1"] -] -Output: 3 -``` - -### Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 300` -- `grid[i][j]` is `'0'` or `'1'`. - -# Thoughts -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Finding the number of islands is to find the number of `connected components`. - -Walk from one vertex (land) to the adjacent vertices until all vertices on the island are visited. - -## Steps -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * Mark each found land as `V` which represents `visited`. Visited lands don't need to be visited again. -1. After all lands on an island have been visited, look for the next non-visited land. -1. Repeat the above two steps until all the lands have been `visited`. - -### Solution 1: 'Depth-First Search' by Recursion -Please click [Depth-First Search by Recursion Solution](200-number-of-islands.md) for `200. Number of Islands` to view. - -## Solution 2: 'Depth-First Search' by Iteration -![](../../images/binary_tree_DFS_1.png) - -In solution 1, we have known how to traverse a graph by recursion. Computer language support for recursive calls is implemented through stacks. -For every recursive solution, there is an iterative solution, which means the same problem can be solved using loops. -The benefit of using iteration is better program performance. After all, recursive calls are expensive. - -Maintaining a stack by yourself can accomplish the same function as recursive calls. - -From this sample code bellow, you can see that starting from a vertex, through recursive calls, it goes up until it can't go any further, turns right, and continues up. The priority order of directions is `up, right, down, left`. -```java -vertexStack.push({i, j - 1}); // left -vertexStack.push({i + 1, j}); // down -vertexStack.push({i, j + 1}); // right -vertexStack.push({i - 1, j}); // up -``` - -## Solution 3: Breadth-First Search -Please click [Breadth-First Search Solution](200-number-of-islands-3.md) for `200. Number of Islands` to view. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -# Python -```python -class Solution: - def __init__(self): - self.grid = None - self.vertex_stack = [] - - def numIslands(self, grid: List[List[str]]) -> int: - island_count = 0 - self.grid = grid - - for i, row in enumerate(grid): - for j, value in enumerate(row): - if value == '1': - island_count += 1 - - self.depth_first_search((i, j)) - - return island_count - - def depth_first_search(self, vertex): - self.vertex_stack.append(vertex) - - while self.vertex_stack: - i, j = self.vertex_stack.pop() - - if i < 0 or i >= len(self.grid): - continue - - if j < 0 or j >= len(self.grid[0]): - continue - - if self.grid[i][j] != '1': - continue - - self.grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - self.vertex_stack.append((i, j - 1)) - self.vertex_stack.append((i + 1, j)) - self.vertex_stack.append((i, j + 1)) - self.vertex_stack.append((i - 1, j)) -``` - -# Java -```java -class Solution { - Stack vertexStack = new Stack<>(); - char[][] grid; - - public int numIslands(char[][] grid) { - this.grid = grid; - var islandCount = 0; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == '1') { - islandCount++; - - depthFirstSearch(new int[]{i, j}); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int[] vertex) { - vertexStack.push(vertex); - - while (!vertexStack.empty()) { - vertex = vertexStack.pop(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.length) { - continue; - } - - if (j < 0 || j >= grid[0].length) { - continue; - } - - if (grid[i][j] != '1') { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.push(new int[]{i, j - 1}); - vertexStack.push(new int[]{i + 1, j}); - vertexStack.push(new int[]{i, j + 1}); - vertexStack.push(new int[]{i - 1, j}); - } - } -} -``` - -# C++ -```cpp -class Solution { -public: - int numIslands(vector>& grid) { - grid_ = grid; - auto island_count = 0; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == '1') { - island_count++; - - depth_first_search(i, j); - } - } - } - - return island_count; - } - -private: - vector> grid_; - stack> vertex_stack; - - void depth_first_search(int i1, int j1) { - vertex_stack.push({i1, j1}); - - while (!vertex_stack.empty()) { - pair vertex = vertex_stack.top(); - vertex_stack.pop(); - - int i = vertex.first; - int j = vertex.second; - - if (i < 0 || i >= grid_.size()) { - continue; - } - - if (j < 0 || j >= grid_[0].size()) { - continue; - } - - if (grid_[i][j] != '1') { - continue; - } - - grid_[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertex_stack.push({i, j - 1}); - vertex_stack.push({i + 1, j}); - vertex_stack.push({i, j + 1}); - vertex_stack.push({i - 1, j}); - } - } -}; -``` - -# JavaScript -```JavaScript -let grid -let vertexStack - -var numIslands = function (grid_) { - grid = grid_ - vertexStack = [] - let islandCount = 0 - - grid.forEach((row, i) => { - row.forEach((item, j) => { - if (item === '1') { - islandCount++ - - depthFirstSearch([i, j]) - } - }) - }) - - return islandCount -}; - -function depthFirstSearch(vertex) { - vertexStack.push(vertex) - - while (vertexStack.length > 0) { - const [i, j] = vertexStack.pop() - - if (i < 0 || i >= grid.length) { - continue - } - - if (j < 0 || j >= grid[0].length) { - continue - } - - if (grid[i][j] != '1') { - continue - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.push([i, j - 1]) - vertexStack.push([i + 1, j]) - vertexStack.push([i, j + 1]) - vertexStack.push([i - 1, j]) - } -} -``` - -# C# -```c# -public class Solution -{ - Stack vertexStack = new Stack(); - char[][] grid; - - public int NumIslands(char[][] grid) - { - this.grid = grid; - int islandCount = 0; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == '1') - { - islandCount++; - - depthFirstSearch([i, j]); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int[] vertex) - { - vertexStack.Push(vertex); - - while (vertexStack.Count > 0) - { - vertex = vertexStack.Pop(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.Length) - { - continue; - } - if (j < 0 || j >= grid[0].Length) - { - continue; - } - if (grid[i][j] != '1') - { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.Push([i, j - 1]); - vertexStack.Push([i + 1, j]); - vertexStack.Push([i, j + 1]); - vertexStack.Push([i - 1, j]); - } - } -} -``` - -# Go -```go -var grid [][]byte -var vertexStack = arraystack.New() - -func numIslands(grid_ [][]byte) int { - grid = grid_ - vertexStack.Clear() - islandCount := 0 - - for i, row := range grid { - for j, value := range row { - if value == '1' { - islandCount++ - - depthFirstSearch([]int{i, j}) - } - } - } - - return islandCount -} - -func depthFirstSearch(vertex []int) { - vertexStack.Push(vertex) - - for !vertexStack.Empty() { - vertex, _ := vertexStack.Pop(); - - i := vertex.([]int)[0] - j := vertex.([]int)[1] - - if i < 0 || i >= len(grid) { - continue - } - - if j < 0 || j >= len(grid[0]) { - continue - } - - if grid[i][j] != '1' { - continue - } - - grid[i][j] = 'V' // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.Push([]int{i, j - 1}) - vertexStack.Push([]int{i + 1, j}) - vertexStack.Push([]int{i, j + 1}) - vertexStack.Push([]int{i - 1, j}) - } -} -``` - -# Ruby -```ruby -def num_islands(grid) - @grid = grid - @vertex_stack = [] - island_count = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == '1' - depth_first_search([i, j]) - - island_count += 1 - end - end - end - - island_count -end - -def depth_first_search(vertex) - @vertex_stack << vertex - - while !@vertex_stack.empty? - vertex = @vertex_stack.pop - - i = vertex[0] - j = vertex[1] - - next if i < 0 || i >= @grid.size - - next if j < 0 || j >= @grid[0].size - - next if @grid[i][j] != '1' - - @grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - @vertex_stack << [i, j - 1] - @vertex_stack << [i + 1, j] - @vertex_stack << [i, j + 1] - @vertex_stack << [i - 1, j] - end -end -``` - -# C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/200-number-of-islands-3.md b/en/1-1000/200-number-of-islands-3.md deleted file mode 100644 index dc9e3e5..0000000 --- a/en/1-1000/200-number-of-islands-3.md +++ /dev/null @@ -1,468 +0,0 @@ -# 200. Number of Islands (Solution 3: Breadth-First Search) -LeetCode link: [200. Number of Islands](https://leetcode.com/problems/number-of-islands/) - -## LeetCode problem description -Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return the number of islands. - -An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - -### Example 1 -``` -Input: grid = [ - ["1","1","1","1","0"], - ["1","1","0","1","0"], - ["1","1","0","0","0"], - ["0","0","0","0","0"] -] -Output: 1 -``` - -### Example 2 -``` -Input: grid = [ - ["1","1","0","0","0"], - ["1","1","0","0","0"], - ["0","0","1","0","0"], - ["0","0","0","1","1"] -] -Output: 3 -``` - -### Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 300` -- `grid[i][j]` is `'0'` or `'1'`. - -# Thoughts -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Finding the number of islands is to find the number of `connected components`. - -Walk from one vertex (land) to the adjacent vertices until all vertices on the island are visited. - -## Steps -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * Mark each found land as `V` which represents `visited`. Visited lands don't need to be visited again. -1. After all lands on an island have been visited, look for the next non-visited land. -1. Repeat the above two steps until all the lands have been `visited`. - -### Solution 1: 'Depth-First Search' by Recursion -Please click [Depth-First Search by Recursion Solution](200-number-of-islands.md) for `200. Number of Islands` to view. - -## Solution 2: 'Depth-First Search' by Iteration -Please click [Depth-First Search by Iteration Solution](200-number-of-islands-2.md) for `200. Number of Islands` to view. - -## Solution 3: Breadth-First Search -![](../../images/binary_tree_BFS_1.gif) - -As shown in the figure above, **Breadth-First Search** can be thought of as visiting vertices in rounds and rounds. - -`Breadth-First Search` emphasizes first-in-first-out, so a **queue** is needed. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Python -```python -class Solution: - def __init__(self): - self.grid = None - self.vertex_queue = deque() - - def numIslands(self, grid: List[List[str]]) -> int: - island_count = 0 - self.grid = grid - - for i, row in enumerate(grid): - for j, value in enumerate(row): - if value == '1': - island_count += 1 - - self.breadth_first_search((i, j)) - - return island_count - - def breadth_first_search(self, vertex): - self.vertex_queue.append(vertex) - - while self.vertex_queue: - i, j = self.vertex_queue.popleft() - - if i < 0 or i >= len(self.grid): - continue - - if j < 0 or j >= len(self.grid[0]): - continue - - if self.grid[i][j] != '1': - continue - - self.grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - self.vertex_queue.append((i - 1, j)) - self.vertex_queue.append((i, j + 1)) - self.vertex_queue.append((i + 1, j)) - self.vertex_queue.append((i, j - 1)) -``` - -## Java -```java -class Solution { - Queue vertexQueue = new ArrayDeque<>(); - char[][] grid; - - public int numIslands(char[][] grid) { - this.grid = grid; - var islandCount = 0; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == '1') { - islandCount++; - - breadthFirstSearch(new int[]{i, j}); - } - } - } - - return islandCount; - } - - void breadthFirstSearch(int[] vertex) { - vertexQueue.add(vertex); - - while (!vertexQueue.isEmpty()) { - vertex = vertexQueue.poll(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.length) { - continue; - } - - if (j < 0 || j >= grid[0].length) { - continue; - } - - if (grid[i][j] != '1') { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.add(new int[]{i - 1, j}); - vertexQueue.add(new int[]{i, j + 1}); - vertexQueue.add(new int[]{i + 1, j}); - vertexQueue.add(new int[]{i, j - 1}); - } - } -} -``` - -## C++ -```cpp -class Solution { -private: - vector> grid_; - queue> vertex_queue; - - void breadth_first_search(int i1, int j1) { - vertex_queue.push({i1, j1}); - - while (!vertex_queue.empty()) { - pair vertex = vertex_queue.front(); - vertex_queue.pop(); - - int i = vertex.first; - int j = vertex.second; - - if (i < 0 || i >= grid_.size()) { - continue; - } - - if (j < 0 || j >= grid_[0].size()) { - continue; - } - - if (grid_[i][j] != '1') { - continue; - } - - grid_[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertex_queue.push({i - 1, j}); - vertex_queue.push({i, j + 1}); - vertex_queue.push({i + 1, j}); - vertex_queue.push({i, j - 1}); - } - } - -public: - int numIslands(vector>& grid) { - grid_ = grid; - auto island_count = 0; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == '1') { - island_count++; - - breadth_first_search(i, j); - } - } - } - - return island_count; - } -}; -``` - -## JavaScript -```JavaScript -let grid -let vertexQueue - -var numIslands = function (grid_) { - grid = grid_ - vertexQueue = new Queue() // github.com/datastructures-js/queue - let islandCount = 0 - - grid.forEach((row, i) => { - row.forEach((item, j) => { - if (item === '1') { - islandCount++ - - breadthFirstSearch([i, j]) - } - }) - }) - - return islandCount -}; - -function breadthFirstSearch(vertex) { - vertexQueue.enqueue(vertex) - - while (!vertexQueue.isEmpty()) { - const [i, j] = vertexQueue.dequeue() - - if (i < 0 || i >= grid.length) { - continue - } - - if (j < 0 || j >= grid[0].length) { - continue - } - - if (grid[i][j] != '1') { - continue - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.enqueue([i - 1, j]) - vertexQueue.enqueue([i, j + 1]) - vertexQueue.enqueue([i + 1, j]) - vertexQueue.enqueue([i, j - 1]) - } -} -``` - -## C# -```c# -public class Solution -{ - Queue vertexQueue = new Queue(); - char[][] grid; - - public int NumIslands(char[][] grid) - { - this.grid = grid; - int islandCount = 0; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == '1') - { - islandCount++; - - breadthFirstSearch([i, j]); - } - } - } - - return islandCount; - } - - void breadthFirstSearch(int[] vertex) - { - vertexQueue.Enqueue(vertex); - - while (vertexQueue.Count > 0) - { - vertex = vertexQueue.Dequeue(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.Length) - { - continue; - } - - if (j < 0 || j >= grid[0].Length) - { - continue; - } - - if (grid[i][j] != '1') - { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.Enqueue([i - 1, j]); - vertexQueue.Enqueue([i, j + 1]); - vertexQueue.Enqueue([i + 1, j]); - vertexQueue.Enqueue([i, j - 1]); - } - } -} -``` - -## Go -```go -var grid [][]byte -var vertexQueue = linkedlistqueue.New() - -func numIslands(grid_ [][]byte) int { - grid = grid_ - vertexQueue.Clear() - islandCount := 0 - - for i, row := range grid { - for j, value := range row { - if value == '1' { - islandCount++ - - breadthFirstSearch([]int{i, j}) - } - } - } - - return islandCount -} - -func breadthFirstSearch(vertex []int) { - vertexQueue.Enqueue(vertex) - - for !vertexQueue.Empty() { - vertex, _ := vertexQueue.Dequeue(); - - i := vertex.([]int)[0] - j := vertex.([]int)[1] - - if i < 0 || i >= len(grid) { - continue - } - - if j < 0 || j >= len(grid[0]) { - continue - } - - if grid[i][j] != '1' { - continue - } - - grid[i][j] = 'V' // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.Enqueue([]int{i - 1, j}) - vertexQueue.Enqueue([]int{i, j + 1}) - vertexQueue.Enqueue([]int{i + 1, j}) - vertexQueue.Enqueue([]int{i, j - 1}) - } -} -``` - -## Ruby -```ruby -def num_islands(grid) - @grid = grid - @vertex_queue = Containers::Queue.new - island_count = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == '1' - breadth_first_search([i, j]) - - island_count += 1 - end - end - end - - island_count -end - -def breadth_first_search(vertex) - @vertex_queue.push(vertex) - - while !@vertex_queue.empty? - vertex = @vertex_queue.pop - - i = vertex[0] - j = vertex[1] - - next if i < 0 || i >= @grid.size - - next if j < 0 || j >= @grid[0].size - - next if @grid[i][j] != '1' - - @grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - @vertex_queue << [i - 1, j] - @vertex_queue << [i, j + 1] - @vertex_queue << [i + 1, j] - @vertex_queue << [i, j - 1] - end -end -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/200-number-of-islands.md b/en/1-1000/200-number-of-islands.md deleted file mode 100644 index 7149d4c..0000000 --- a/en/1-1000/200-number-of-islands.md +++ /dev/null @@ -1,395 +0,0 @@ -# 200. Number of Islands (Solution 1: 'Depth-First Search' by Recursion) -LeetCode link: [200. Number of Islands](https://leetcode.com/problems/number-of-islands/) - -# LeetCode problem description -Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return the number of islands. - -An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - -## Example 1 -``` -Input: grid = [ - ["1","1","1","1","0"], - ["1","1","0","1","0"], - ["1","1","0","0","0"], - ["0","0","0","0","0"] -] -Output: 1 -``` - -## Example 2 -``` -Input: grid = [ - ["1","1","0","0","0"], - ["1","1","0","0","0"], - ["0","0","1","0","0"], - ["0","0","0","1","1"] -] -Output: 3 -``` - -## Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 300` -- `grid[i][j]` is `'0'` or `'1'`. - -# Intuition -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Finding the number of islands is to find the number of `connected components`. - -Walk from one vertex (land) to the adjacent vertices until all vertices on the island are visited. - -## Approach -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * Mark each found land as `V` which represents `visited`. Visited lands don't need to be visited again. -1. After all lands on an island have been visited, look for the next non-visited land. -1. Repeat the above two steps until all the lands have been `visited`. - -## Solution 1: 'Depth-First Search' by Recursion -![](../../images/binary_tree_DFS_1.png) - -From this sample code bellow, you can see that starting from a vertex, through recursive calls, it goes up until it can't go any further, turns right, and continues up. The priority order of directions is `up, right, down, left`. -```java -depth_first_search(i - 1, j); // up -depth_first_search(i, j + 1); // right -depth_first_search(i + 1, j); // down -depth_first_search(i, j - 1); // left -``` - -## Solution 2: 'Depth-First Search' by Iteration -Please click [Depth-First Search by Iteration Solution](200-number-of-islands-2.md) for `200. Number of Islands` to view. - -## Solution 3: Breadth-First Search -Please click [Breadth-First Search Solution](200-number-of-islands-3.md) for `200. Number of Islands` to view. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -# Python -```python -class Solution: - def __init__(self): - self.grid = None - - def numIslands(self, grid: List[List[str]]) -> int: - self.grid = grid - island_count = 0 - - for i, row in enumerate(grid): - for j, value in enumerate(row): - if value == '1': - island_count += 1 - - self.depth_first_search(i, j) - - return island_count - - def depth_first_search(self, i, j): - if i < 0 or i >= len(self.grid): - return - - if j < 0 or j >= len(self.grid[0]): - return - - if self.grid[i][j] != '1': - return - - self.grid[i][j] = 'V' - - self.depth_first_search(i - 1, j) - self.depth_first_search(i, j + 1) - self.depth_first_search(i + 1, j) - self.depth_first_search(i, j - 1) -``` - -# Java -```java -class Solution { - char[][] grid; - - public int numIslands(char[][] grid) { - this.grid = grid; - var islandCount = 0; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == '1') { - islandCount++; - - depthFirstSearch(i, j); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int i, int j) { - if (i < 0 || i >= grid.length) { - return; - } - - if (j < 0 || j >= grid[0].length) { - return; - } - - if (grid[i][j] != '1') { - return; - } - - grid[i][j] = 'V'; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# C++ -```cpp -class Solution { -public: - int numIslands(vector>& grid) { - grid_ = grid; - auto island_count = 0; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == '1') { - island_count++; - - depth_first_search(i, j); - } - } - } - - return island_count; - } - -private: - vector> grid_; - - void depth_first_search(int i, int j) { - if (i < 0 || i >= grid_.size() || - j < 0 || j >= grid_[0].size() || - grid_[i][j] != '1') { - return; - } - - grid_[i][j] = 'V'; - - depth_first_search(i - 1, j); - depth_first_search(i, j + 1); - depth_first_search(i + 1, j); - depth_first_search(i, j - 1); - } -}; -``` - -# JavaScript -```JavaScript -let grid - -var numIslands = function (grid_) { - grid = grid_ - let islandCount = 0 - - grid.forEach((row, i) => { - row.forEach((value, j) => { - if (value === '1') { - islandCount++ - - depthFirstSearch(i, j) - } - }) - }) - - return islandCount -}; - -function depthFirstSearch(i, j) { - if (i < 0 || i >= grid.length) { - return - } - - if (j < 0 || j >= grid[0].length) { - return - } - - if (grid[i][j] != '1') { - return - } - - grid[i][j] = 'V'; - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# C# -```c# -public class Solution -{ - char[][] grid; - - public int NumIslands(char[][] grid) - { - this.grid = grid; - int islandCount = 0; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == '1') - { - islandCount++; - - depthFirstSearch(i, j); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int i, int j) - { - if (i < 0 || i >= grid.Length) - return; - - if (j < 0 || j >= grid[0].Length) - return; - - if (grid[i][j] != '1') - return; - - grid[i][j] = 'V'; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# Go -```go -var grid [][]byte - -func numIslands(grid_ [][]byte) int { - grid = grid_ - islandCount := 0 - - for i, row := range grid { - for j, value := range row { - if value == '1' { - islandCount++ - - depthFirstSearch(i, j) - } - } - } - - return islandCount -} - -func depthFirstSearch(i int, j int) { - if i < 0 || i >= len(grid) { - return - } - - if j < 0 || j >= len(grid[0]) { - return - } - - if grid[i][j] != '1' { - return - } - - grid[i][j] = 'V' - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# Ruby -```Ruby -def num_islands(grid) - @grid = grid - island_count = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == '1' - depth_first_search(i, j) - - island_count += 1 - end - end - end - - island_count -end - -def depth_first_search(i, j) - return if i < 0 || i >= @grid.size - - return if j < 0 || j >= @grid[0].size - - return if @grid[i][j] != '1' - - @grid[i][j] = 'V' - - depth_first_search(i - 1, j) - depth_first_search(i, j + 1) - depth_first_search(i + 1, j) - depth_first_search(i, j - 1) -end -``` - -# C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/202-happy-number.md b/en/1-1000/202-happy-number.md deleted file mode 100644 index e374b25..0000000 --- a/en/1-1000/202-happy-number.md +++ /dev/null @@ -1,280 +0,0 @@ -# 202. Happy Number - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [202. Happy Number - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/202-happy-number) for a better experience! - -LeetCode link: [202. Happy Number](https://leetcode.com/problems/happy-number), difficulty: **Easy**. - -## LeetCode description of "202. Happy Number" - -Write an algorithm to determine if a number `n` is happy. - -A **happy number** is a number defined by the following process: - -- Starting with any positive integer, replace the number by the sum of the squares of its digits. -- Repeat the process until the number equals 1 (where it will stay), or it **loops endlessly in a cycle** which does not include 1. -- Those numbers for which this process **ends in 1** are happy. - -Return `true` if `n` is *a happy number*, and `false` if not. - -### [Example 1] - -**Input**: `n = 19` - -**Output**: `true` - -**Explanation**: - -

12 + 92 = 82
-82 + 22 = 68
-62 + 82 = 100
-12 + 02 + 02 = 1

- - -### [Example 2] - -**Input**: `n = 2` - -**Output**: `false` - -### [Constraints] - -- `1 <= n <= 2^31 - 1` - -## Intuition - -1. It is more convenient to call `isHappy(n)` recursively. You only need to generate a new `n` as a parameter each time. -2. If `n` has already appeared, it means that the loop has been entered, and `return false`. You can use `Set` to save the `n` that has appeared. -3. Go is the iterative solution, other languages are the recursive solution. - -## Step by Step Solutions - -1. Generate a new `n` as the `isHappy(n)` parameter. - - ```javascript - let sum = 0 - - for (const digit of n.toString()) { - sum += Math.pow(Number(digit), 2) - } - - // omitted code - - return isHappy(sum) - ``` - -2. If `n` has already appeared, it means that the loop has been entered, and `return false`. You can use `Set` to save the `n` that has appeared. - - ```javascript - var isHappy = function (n, appearedNums) { // 0 - appearedNums ||= new Set() // 1 - let sum = 0 - - for (const digit of n.toString()) { - sum += Math.pow(Number(digit), 2) - } - - if (sum == 1) { - return true - } - - if (appearedNums.has(sum)) { // 2 - return false - } - - appearedNums.add(sum) // 3 - - return isHappy(sum, appearedNums) - }; - ``` - -## Complexity - -- Time complexity: `O(log N)`. -- Space complexity: `O(log N)`. - -## Java - -```java -class Solution { - private HashSet appearedNums = new HashSet<>(); - - public boolean isHappy(int n) { - appearedNums.add(n); - - var sum = 0; - - for (var digit : String.valueOf(n).toCharArray()) { - sum += Math.pow(digit - '0', 2); - } - - if (sum == 1) { - return true; - } - - if (appearedNums.contains(sum)) { - return false; - } - - return isHappy(sum); - } -} -``` - -## Python - -```python -class Solution: - def __init__(self): - self.appeared_nums = set() - - def isHappy(self, n: int) -> bool: - self.appeared_nums.add(n) - - number = sum([int(digit) ** 2 for digit in str(n)]) - - if number == 1: - return True - - if number in self.appeared_nums: - return False - - return self.isHappy(number) -``` - -## JavaScript - -```javascript -var isHappy = function (n, appearedNums) { - appearedNums ||= new Set() - let sum = 0 - - for (const digit of n.toString()) { - sum += Math.pow(Number(digit), 2) - } - - if (sum == 1) { - return true - } - - if (appearedNums.has(sum)) { - return false - } - - appearedNums.add(sum) - - return isHappy(sum, appearedNums) -}; -``` - -## C# - -```csharp -public class Solution -{ - HashSet appearedNums = new HashSet(); - - public bool IsHappy(int n) - { - appearedNums.Add(n); - - int sum = 0; - - foreach (char digit in n.ToString().ToCharArray()) - sum += (int)Math.Pow(digit - '0', 2); - - if (sum == 1) - return true; - - if (appearedNums.Contains(sum)) - return false; - - return IsHappy(sum); - } -} -``` - -## Go - -```go -func isHappy(n int) bool { - // Use map to track seen numbers - seen := make(map[int]bool) - - for n != 1 && !seen[n] { - seen[n] = true - n = sumOfSquaredDigits(n) - } - - return n == 1 -} - -func sumOfSquaredDigits(n int) int { - sum := 0 - nStr := strconv.Itoa(n) - for i := 0; i < len(nStr); i++ { - digit := int(nStr[i] - '0') - sum += digit * digit - } - return sum -} -``` - -## C++ - -```cpp -class Solution { -public: - bool isHappy(int n) { - if (n == 1) { - return true; - } - - if (appeared_nums_.count(n)) { - return false; - } - - appeared_nums_.insert(n); - - return isHappy(getSum(n)); - } - -private: - unordered_set appeared_nums_; - - int getSum(int n) { - string n_str = to_string(n); - int sum = 0; - for (char digit : n_str) { - sum += (digit - '0') * (digit - '0'); - } - return sum; - } -}; -``` - -## Ruby - -```ruby -def is_happy(n, appeared_nums = Set.new) - return true if n == 1 - return false if appeared_nums.include?(n) - - appeared_nums.add(n) - sum = n.to_s.chars.map { |digit| digit.to_i ** 2 }.sum - - is_happy(sum, appeared_nums) -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [202. Happy Number - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/202-happy-number). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/203-remove-linked-list-elements.md b/en/1-1000/203-remove-linked-list-elements.md deleted file mode 100644 index 9bc79f1..0000000 --- a/en/1-1000/203-remove-linked-list-elements.md +++ /dev/null @@ -1,274 +0,0 @@ -# 203. Remove Linked List Elements - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [203. Remove Linked List Elements - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/203-remove-linked-list-elements) for a better experience! - -LeetCode link: [203. Remove Linked List Elements](https://leetcode.com/problems/remove-linked-list-elements), difficulty: **Easy**. - -## LeetCode description of "203. Remove Linked List Elements" - -Given the `head` of a linked list and an integer `val`, remove all the nodes of the linked list that has `Node.val == val`, and return _the new head_. - -### [Example 1] - -![](../../images/examples/203_1.jpg) - -**Input**: `head = [1,2,6,3,4,5,6], val = 6` - -**Output**: `[1,2,3,4,5]` - -### [Example 2] - -**Input**: `head = [], val = 1` - -**Output**: `[]` - -### [Example 3] - -**Input**: `head = [7,7,7,7], val = 7` - -**Output**: `[]` - -### [Constraints] - -- The number of nodes in the list is in the range `[0, 10000]`. -- `1 <= Node.val <= 50` -- `0 <= val <= 50` - -## Intuition - -- Assume that the node to be deleted in the linked list is `d`, and the previous node of `d` is `p`, so `p.next` is `d`. - - To delete `d`, just set `p.next = p.next.next`. - -- Because `p.next.next` is used, the loop condition should be `while (p.next != null)` instead of `while (p != null)`. - -- But there is no node before the `head` node, which means that the `head` node needs to be treated specially. - - Is there a way to make the `head` node no longer special? In this way, there is no need to treat the `head` specially. - -
Click to view the answer

The way is to introduce a `dummy` node, `dummy.next = head`.

- -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ -class Solution { - public ListNode removeElements(ListNode head, int val) { - var dummyHead = new ListNode(); - dummyHead.next = head; - var node = dummyHead; - - while (node.next != null) { - if (node.next.val == val) { - node.next = node.next.next; - } else { - node = node.next; - } - } - - return dummyHead.next; - } -} -``` - -## Python - -```python -# Definition for singly-linked list. -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: - dummy_head = ListNode() - dummy_head.next = head - node = dummy_head - - while node.next: - if node.next.val == val: - node.next = node.next.next - else: - node = node.next - - return dummy_head.next -``` - -## C++ - -```cpp -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* removeElements(ListNode* head, int val) { - auto dummyHead = new ListNode(); - dummyHead->next = head; - auto node = dummyHead; - - while (node->next != nullptr) { - if (node->next->val == val) { - auto next_node = node->next; - node->next = node->next->next; - delete next_node; - } else { - node = node->next; - } - } - - return dummyHead->next; - } -}; -``` - -## JavaScript - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var removeElements = function (head, val) { - const dummyHead = new ListNode() - dummyHead.next = head - let node = dummyHead - - while (node.next != null) { - if (node.next.val == val) { - node.next = node.next.next - } else { - node = node.next - } - } - - return dummyHead.next -}; -``` - -## C# - -```csharp -/** - * Definition for singly-linked list. - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution { - public ListNode RemoveElements(ListNode head, int val) { - var dummyHead = new ListNode(); - dummyHead.next = head; - var node = dummyHead; - - while (node.next != null) { - if (node.next.val == val) { - node.next = node.next.next; - } else { - node = node.next; - } - } - - return dummyHead.next; - } -} -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func removeElements(head *ListNode, val int) *ListNode { - dummyHead := &ListNode{} - dummyHead.Next = head - node := dummyHead - - for node.Next != nil { - if node.Next.Val == val { - node.Next = node.Next.Next - } else { - node = node.Next - } - } - - return dummyHead.Next -} -``` - -## Ruby - -```ruby -# Definition for singly-linked list. -# class ListNode -# attr_accessor :val, :next -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def remove_elements(head, val) - dummy_head = ListNode.new - dummy_head.next = head - node = dummy_head - - until node.next.nil? - if node.next.val == val - node.next = node.next.next - else - node = node.next - end - end - - dummy_head.next -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [203. Remove Linked List Elements - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/203-remove-linked-list-elements). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/206-reverse-linked-list.md b/en/1-1000/206-reverse-linked-list.md deleted file mode 100644 index bf1bde1..0000000 --- a/en/1-1000/206-reverse-linked-list.md +++ /dev/null @@ -1,295 +0,0 @@ -# 206. Reverse Linked List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [206. Reverse Linked List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/206-reverse-linked-list) for a better experience! - -LeetCode link: [206. Reverse Linked List](https://leetcode.com/problems/reverse-linked-list), difficulty: **Easy**. - -## LeetCode description of "206. Reverse Linked List" - -Given the `head` of a singly linked list, reverse the list, and return _the reversed list_. - -### [Example 1] - -![](../../images/examples/206_1.jpg) - -**Input**: `head = [1,2,3,4,5]` - -**Output**: `[5,4,3,2,1]` - -### [Example 2] - -![](../../images/examples/206_2.jpg) - -**Input**: `[1,2]` - -**Output**: `[2,1]` - -### [Example 3] - -**Input**: `[]` - -**Output**: `[]` - -### [Constraints] - -- The number of nodes in the list is the range `[0, 5000]`. -- `-5000 <= Node.val <= 5000` - -## Intuition - -1. To solve this problem, we only need to define **two** variables: `current` and `previous`. How do we inverse two node? - -
Click to view the answer

`current.next = previous` is the inversion.

- -2. Which should be the loop condition? `while (current != null)` or `while (current.next != null)`? - -
Click to view the answer

It is `while (current != null)`, because the operation to be performed is `current.next = previous`.

- -## Step by Step Solutions - -1. Traverse all nodes. - - ```javascript - previous = null - current = head - - while (current != null) { - current = current.next - } - ``` - -2. Add `current.next = previous`. - - ```javascript - previous = null - current = head - - while (current != null) { - tempNext = current.next - current.next = previous - current = tempNext - } - ``` - -3. Currently `previous` is always `null`, we need to change it: `previous = current`. - - ```javascript - previous = null - current = head - - while (current != null) { - tempNext = current.next - current.next = previous - previous = current - current = tempNext - } - ``` - - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ -class Solution { - public ListNode reverseList(ListNode head) { - ListNode previous = null; - var current = head; - - while (current != null) { - var tempNext = current.next; - current.next = previous; - previous = current; - current = tempNext; - } - - return previous; - } -} -``` - -## Python - -```python -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: - previous = None - current = head - - while current: - temp_next = current.next - current.next = previous - previous = current - current = temp_next - - return previous -``` - -## C++ - -```cpp -/** - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* reverseList(ListNode* head) { - ListNode* previous = nullptr; - ListNode* current = head; - - while (current) { - auto temp_next = current->next; - current->next = previous; - previous = current; - current = temp_next; - } - - return previous; - } -}; -``` - -## JavaScript - -```javascript -/** - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var reverseList = function (head) { - let previous = null - let current = head - - while (current != null) { - const tempNext = current.next - current.next = previous - previous = current - current = tempNext - } - - return previous -}; -``` - -## C# - -```csharp -/** - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution -{ - public ListNode ReverseList(ListNode head) - { - ListNode previous = null; - ListNode current = head; - - while (current != null) - { - var tempNext = current.next; - current.next = previous; - previous = current; - current = tempNext; - } - - return previous; - } -} -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func reverseList(head *ListNode) *ListNode { - var previous *ListNode - current := head - - for current != nil { - tempNext := current.Next - current.Next = previous - previous = current - current = tempNext - } - - return previous -} -``` - -## Ruby - -```ruby -# class ListNode -# attr_accessor :val, :next -# -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def reverse_list(head) - previous = nil - current = head - - while current - temp_next = current.next - current.next = previous - previous = current - current = temp_next - end - - previous -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [206. Reverse Linked List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/206-reverse-linked-list). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/207-course-schedule.md b/en/1-1000/207-course-schedule.md deleted file mode 100644 index 684d651..0000000 --- a/en/1-1000/207-course-schedule.md +++ /dev/null @@ -1,430 +0,0 @@ -# 207. Course Schedule - Best Practices of LeetCode Solutions -LeetCode link: [207. Course Schedule](https://leetcode.com/problems/course-schedule) - -## LeetCode problem description -There are a total of `numCourses` courses you have to take, labeled from `0` to `numCourses - 1`. You are given an array `prerequisites` where `prerequisites[i] = [ai, bi]` indicates that you **must** take course `bi` first if you want to take course `ai`. - -* For example, the pair `[0, 1]`, indicates that to take course `0` you have to first take course `1`. - -Return `true` if you can finish all courses. Otherwise, return `false`. - -### Example 1 -```ruby -Input: numCourses = 2, prerequisites = [[1,0]] -Output: true -Explanation: There are a total of 2 courses to take. -To take course 1 you should have finished course 0. So it is possible. -``` - -### Example 2 -```ruby -Input: numCourses = 2, prerequisites = [[1,0],[0,1]] -Output: false -Explanation: There are a total of 2 courses to take. -To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible. -``` - -### Constraints -- `1 <= numCourses <= 2000` -- `0 <= prerequisites.length <= 5000` -- `prerequisites[i].length == 2` -- `0 <= ai, bi < numCourses` -- All the pairs `prerequisites[i]` are **unique**. - -## Intuition -- Each course can be abstracted as a vertex in a graph. -- The existence of a dependency relationship indicates that it is a directed graph. - -## Approach 1 -- Course A depends on course B, which can be abstracted as course A needs course B to unlock, and the in-degree of course A needs to be increased by 1. -- So an `in_degrees` array is needed to save the in-degree of each course. -- Courses with an in-degree of 0 can be studied first, so they can be put into a **queue** and processed one by one. -- Courses with an in-degree of 0 unlock other courses. This is the direction of the directed graph. Don't get it wrong. -- After each course is completed, the in-degree of other courses that depend on it is reduced by 1. If it is found that the in-degree of the course is 0 after deducting 1, the course is added to the queue. -- Which courses can be unlocked by a course need to be saved with a map or an array `courses_list`. -- If the in-degree of all courses is 0 at the end, return `true`, otherwise it means that there is a **cycle** in the directed graph, and return `false`. -- The above algorithm is a _breadth-first algorithm_. - -## Approach 2 -- Can you use a _depth-first algorithm_ to solve it? -- Simply replacing the queue used in the _breadth-first_ algorithm with a **stack** will create a _depth-first_ algorithm. - -## Complexity -`V` is `vertices.length`. - -`E` is `edges.length`. - -* Time: `O(V + E)`. -* Space: `O(V + E)`. - -## Python -### Solution 1: Breadth-First Search -```python -from collections import deque - -class Solution: - def canFinish(self, num_courses: int, prerequisites: List[List[int]]) -> bool: - courses_list = [set() for _ in range(num_courses)] # index: course, value: courses depend on course - in_degrees = [0] * num_courses - - for course_item, course in prerequisites: - courses_list[course].add(course_item) - in_degrees[course_item] += 1 - - ok_course_queue = deque( - [i for i, in_degree in enumerate(in_degrees) if in_degree == 0] - ) - - while ok_course_queue: - ok_course = ok_course_queue.popleft() - - for course in courses_list[ok_course]: - in_degrees[course] -= 1 - - if in_degrees[course] == 0: - ok_course_queue.append(course) - - return sum(in_degrees) == 0 -``` - -### Solution 2: Depth-First Search -```python -class Solution: - def canFinish(self, num_courses: int, prerequisites: List[List[int]]) -> bool: - courses_list = [set() for _ in range(num_courses)] # index: course, value: courses depend on course - in_degrees = [0] * num_courses - - for prerequisite in prerequisites: - courses_list[prerequisite[1]].add(prerequisite[0]) - in_degrees[prerequisite[0]] += 1 - - ok_courses = [i for i, in_degree in enumerate(in_degrees) if in_degree == 0] - - while ok_courses: - ok_course = ok_courses.pop() - - for course in courses_list[ok_course]: - in_degrees[course] -= 1 - - if in_degrees[course] == 0: - ok_courses.append(course) - - return sum(in_degrees) == 0 -``` - -## Java -### Solution 1: Breadth-First Search -```java -class Solution { - public boolean canFinish(int numCourses, int[][] prerequisites) { - var inDegrees = new int[numCourses]; - var coursesList = new ArrayList>(); // index: course, value: courses depend on course - for (var i = 0; i < numCourses; i++) { - coursesList.add(new HashSet()); - } - - for (var prerequisite : prerequisites) { - inDegrees[prerequisite[0]]++; - - var courses = coursesList.get(prerequisite[1]); - courses.add(prerequisite[0]); - } - - var okCourses = new ArrayDeque(); - var studiedCourseCount = 0; - - for (var course = 0; course < inDegrees.length; course++) { - if (inDegrees[course] == 0) { - okCourses.add(course); - } - } - - while (!okCourses.isEmpty()) { - var okCourse = okCourses.poll(); - studiedCourseCount++; - - for (var course : coursesList.get(okCourse)) { - inDegrees[course]--; - - if (inDegrees[course] == 0) { - okCourses.add(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -### Solution 2: Depth-First Search -```java -class Solution { - public boolean canFinish(int numCourses, int[][] prerequisites) { - var inDegrees = new int[numCourses]; - var coursesList = new ArrayList>(); // index: course, value: courses depend on course - for (var i = 0; i < numCourses; i++) { - coursesList.add(new HashSet()); - } - - for (var prerequisite : prerequisites) { - inDegrees[prerequisite[0]]++; - - var courses = coursesList.get(prerequisite[1]); - courses.add(prerequisite[0]); - } - - var okCourses = new Stack(); - var studiedCourseCount = 0; - - for (var course = 0; course < inDegrees.length; course++) { - if (inDegrees[course] == 0) { - okCourses.push(course); - } - } - - while (!okCourses.isEmpty()) { - var okCourse = okCourses.pop(); - studiedCourseCount++; - - for (var course : coursesList.get(okCourse)) { - inDegrees[course]--; - - if (inDegrees[course] == 0) { - okCourses.push(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -## C++ -### Solution 1: Breadth-First Search -```cpp -class Solution { -public: - bool canFinish(int num_courses, vector>& prerequisites) { - auto in_degrees = vector(num_courses); - auto courses_vector = vector>(num_courses); // index: course, value: courses depend on course - - for (auto& prerequisite : prerequisites) { - in_degrees[prerequisite[0]]++; - - courses_vector[prerequisite[1]].insert(prerequisite[0]); - } - - queue ok_courses; - auto studied_course_count = 0; - - for (auto course = 0; course < in_degrees.size(); course++) { - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - - while (!ok_courses.empty()) { - auto okCourse = ok_courses.front(); - ok_courses.pop(); - studied_course_count++; - - for (auto course : courses_vector[okCourse]) { - in_degrees[course]--; - - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - } - - return studied_course_count == num_courses; - } -}; -``` - -### Solution 2: Depth-First Search -```cpp -class Solution { -public: - bool canFinish(int num_courses, vector>& prerequisites) { - auto in_degrees = vector(num_courses); - auto courses_vector = vector>(num_courses); // index: course, value: courses depend on course - - for (auto& prerequisite : prerequisites) { - in_degrees[prerequisite[0]]++; - - courses_vector[prerequisite[1]].insert(prerequisite[0]); - } - - stack ok_courses; - auto studied_course_count = 0; - - for (auto course = 0; course < in_degrees.size(); course++) { - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - - while (!ok_courses.empty()) { - auto okCourse = ok_courses.top(); - ok_courses.pop(); - studied_course_count++; - - for (auto course : courses_vector[okCourse]) { - in_degrees[course]--; - - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - } - - return studied_course_count == num_courses; - } -}; -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -### Solution 1: Breadth-First Search -```c# -public class Solution { - public bool CanFinish(int numCourses, int[][] prerequisites) - { - var inDegrees = new int[numCourses]; - var coursesList = new List>(); // index: course, value: courses depend on course - - for (int i = 0; i < numCourses; i++) - coursesList.Add(new HashSet()); - - foreach (int[] prerequisite in prerequisites) - { - inDegrees[prerequisite[0]]++; - - var courses = coursesList[prerequisite[1]]; - courses.Add(prerequisite[0]); - } - - var okCourses = new Queue(); - int studiedCourseCount = 0; - - for (int course = 0; course < inDegrees.Length; course++) - { - if (inDegrees[course] == 0) - { - okCourses.Enqueue(course); - } - } - - while (okCourses.Count > 0) - { - int okCourse = okCourses.Dequeue(); - studiedCourseCount++; - - foreach (int course in coursesList[okCourse]) - { - inDegrees[course]--; - - if (inDegrees[course] == 0) - { - okCourses.Enqueue(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -### Solution 2: Depth-First Search -```c# -public class Solution { - public bool CanFinish(int numCourses, int[][] prerequisites) - { - var inDegrees = new int[numCourses]; - var coursesList = new List>(); // index: course, value: courses depend on course - - for (int i = 0; i < numCourses; i++) - coursesList.Add(new HashSet()); - - foreach (int[] prerequisite in prerequisites) - { - inDegrees[prerequisite[0]]++; - - var courses = coursesList[prerequisite[1]]; - courses.Add(prerequisite[0]); - } - - var okCourses = new Stack(); - int studiedCourseCount = 0; - - for (int course = 0; course < inDegrees.Length; course++) - { - if (inDegrees[course] == 0) - { - okCourses.Push(course); - } - } - - while (okCourses.Count > 0) - { - int okCourse = okCourses.Pop(); - studiedCourseCount++; - - foreach (int course in coursesList[okCourse]) - { - inDegrees[course]--; - - if (inDegrees[course] == 0) - { - okCourses.Push(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/209-minimum-size-subarray-sum.md b/en/1-1000/209-minimum-size-subarray-sum.md deleted file mode 100644 index 5a5ada0..0000000 --- a/en/1-1000/209-minimum-size-subarray-sum.md +++ /dev/null @@ -1,302 +0,0 @@ -# 209. Minimum Size Subarray Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [209. Minimum Size Subarray Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/209-minimum-size-subarray-sum) for a better experience! - -LeetCode link: [209. Minimum Size Subarray Sum](https://leetcode.com/problems/minimum-size-subarray-sum), difficulty: **Medium**. - -## LeetCode description of "209. Minimum Size Subarray Sum" - -Given an array of positive integers `nums` and a positive integer `target`, return *the* ***minimal length*** *of a* ***subarray*** *whose sum is greater than or equal to `target`*. If there is no such subarray, return `0` instead. - -> A **subarray** is a contiguous non-empty sequence of elements within an array. - -### [Example 1] - -**Input**: `target = 7, nums = [2,3,1,2,4,3]` - -**Output**: `2` - -**Explanation**: - -

The subarray [4,3] has the minimal length under the problem constraint.

- - -### [Example 2] - -**Input**: `target = 4, nums = [1,4,4]` - -**Output**: `1` - -**Explanation**: `target = 11, nums = [1,1,1,1,1,1,1,1]` - -### [Example 3] - -**Input**: `target = 11, nums = [1,1,1,1,1,1,1,1]` - -**Output**: `0` - -### [Constraints] - -- `1 <= target <= 10^9` -- `1 <= nums.length <= 10^5` -- `1 <= nums[i] <= 10^4` - -## Intuition - -For **subarray** problems, you can consider using **Sliding Window Technique**, which is similar to the **Fast & Slow Pointers Approach**. - -## Step by Step Solutions - -1. Iterate over the `nums` array, the `index` of the element is named `fastIndex`. Although inconspicuous, this is the most important logic of the *Fast & Slow Pointers Approach*. Please memorize it. - -2. `sum += nums[fast_index]`. - - ```java - var minLength = Integer.MAX_VALUE; - var sum = 0; - var slowIndex = 0; - - for (var fastIndex = 0; fastIndex < nums.length; fastIndex++) { // This line the most important logic of the `Fast and Slow Pointers Technique`. - sum += nums[fastIndex]; // 1 - } - - return minLength; - ``` - -3. Control of `slowIndex`: - - ```java - var minLength = Integer.MAX_VALUE; - var sum = 0; - var slowIndex = 0; - - for (var fastIndex = 0; fastIndex < nums.length; fastIndex++) { - sum += nums[fastIndex]; - - while (sum >= target) { // 1 - minLength = Math.min(minLength, fastIndex - slowIndex + 1); // 2 - sum -= nums[slowIndex]; // 3 - slowIndex++; // 4 - } - } - - if (minLength == Integer.MAX_VALUE) { // 5 - return 0; // 6 - } - - return minLength; - ``` - - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -class Solution { - public int minSubArrayLen(int target, int[] nums) { - var minLength = Integer.MAX_VALUE; - var sum = 0; - var slowIndex = 0; - - for (var fastIndex = 0; fastIndex < nums.length; fastIndex++) { // This line is the most important. You'd better memorize it. - sum += nums[fastIndex]; - - while (sum >= target) { - minLength = Math.min(minLength, fastIndex - slowIndex + 1); - sum -= nums[slowIndex]; - slowIndex++; - } - } - - if (minLength == Integer.MAX_VALUE) { - return 0; - } - - return minLength; - } -} -``` - -## Python - -```python -class Solution: - def minSubArrayLen(self, target: int, nums: List[int]) -> int: - min_length = float('inf') - sum_ = 0 - slow_index = 0 - - for fast_index, num in enumerate(nums): # This line is the most important. You'd better memorize it. - sum_ += num - - while sum_ >= target: - min_length = min(min_length, fast_index - slow_index + 1) - sum_ -= nums[slow_index] - slow_index += 1 - - if min_length == float('inf'): - return 0 - - return min_length -``` - -## JavaScript - -```javascript -var minSubArrayLen = function (target, nums) { - let minLength = Number.MAX_SAFE_INTEGER - let sum = 0 - let slowIndex = 0 - - nums.forEach((num, fastIndex) => { // This line is the most important. You'd better memorize it. - sum += num - - while (sum >= target) { - minLength = Math.min(minLength, fastIndex - slowIndex + 1) - sum -= nums[slowIndex] - slowIndex++ - } - }) - - if (minLength == Number.MAX_SAFE_INTEGER) { - return 0 - } - - return minLength -}; -``` - -## C# - -```csharp -public class Solution -{ - public int MinSubArrayLen(int target, int[] nums) - { - int minLength = Int32.MaxValue; - int sum = 0; - int slowIndex = 0; - - for (int fastIndex = 0; fastIndex < nums.Length; fastIndex++) // This line is the most important. You'd better memorize it. - { - sum += nums[fastIndex]; - - while (sum >= target) - { - minLength = Math.Min(minLength, fastIndex - slowIndex + 1); - sum -= nums[slowIndex]; - slowIndex++; - } - } - - if (minLength == Int32.MaxValue) - return 0; - - return minLength; - } -} -``` - -## Go - -```go -func minSubArrayLen(target int, nums []int) int { - minLength := math.MaxInt32 - sum := 0 - slowIndex := 0 - - for fastIndex := 0; fastIndex < len(nums); fastIndex++ { // This line is the most important. You'd better memorize it. - sum += nums[fastIndex] - - for sum >= target { - minLength = min(minLength, fastIndex - slowIndex + 1) - sum -= nums[slowIndex] - slowIndex++ - } - } - - if minLength == math.MaxInt32 { - return 0 - } - - return minLength -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} -``` - -## Ruby - -```ruby -# @param {Integer} target -# @param {Integer[]} nums -# @return {Integer} -def min_sub_array_len(target, nums) - min_length = Float::INFINITY - sum = 0 - slow_index = 0 - - nums.each_with_index do |num, fast_index| # This line is the most important. You'd better memorize it. - sum += num - - while sum >= target - min_length = [min_length, fast_index - slow_index + 1].min - sum -= nums[slow_index] - slow_index += 1 - end - end - - min_length == Float::INFINITY ? 0 : min_length -end -``` - -## C++ - -```cpp -class Solution { -public: - int minSubArrayLen(int target, vector& nums) { - int min_length = INT_MAX; - int sum = 0; - int slow_index = 0; - - for (int fast_index = 0; fast_index < nums.size(); fast_index++) { - sum += nums[fast_index]; - - while (sum >= target) { - min_length = min(min_length, fast_index - slow_index + 1); - sum -= nums[slow_index]; - slow_index++; - } - } - - if (min_length == INT_MAX) { - return 0; - } - - return min_length; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [209. Minimum Size Subarray Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/209-minimum-size-subarray-sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/213-house-robber-ii.md b/en/1-1000/213-house-robber-ii.md deleted file mode 100644 index a7f5d4b..0000000 --- a/en/1-1000/213-house-robber-ii.md +++ /dev/null @@ -1,149 +0,0 @@ -# 213. House Robber II -LeetCode link: [213. House Robber II](https://leetcode.com/problems/house-robber-ii/) - -## LeetCode problem description -You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are **arranged in a circle**. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and **it will automatically contact the police if two adjacent houses were broken into on the same night**. - -Given an integer array `nums` representing the amount of money of each house, return the maximum amount of money you can rob tonight **without alerting the police**. - -``` ----------------------------------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [2,3,2] -Output: 3 -Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses. ----------------------------------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [1,2,3,1] -Output: 4 -Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). - Total amount you can rob = 1 + 3 = 4. ----------------------------------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums = [1,2,3] -Output: 3 ----------------------------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 100 -0 <= nums[i] <= 1000 ----------------------------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Solution 1 -```python -class Solution: - def rob(self, nums: List[int]) -> int: - if len(nums) <= 2: - return max(nums) - - return max( - max_money_robbed(nums[1:]), - max_money_robbed(nums[:-1]) - ) - -def max_money_robbed(nums): - dp = [0] * len(nums) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i in range(2, len(dp)): - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var rob = function (nums) { - if (nums.length <= 2) { - return Math.max(...nums) - } - - return Math.max( - maxMoneyRobbed(nums.slice(1,)), - maxMoneyRobbed(nums.slice(0, nums.length - 1)) - ) -}; - -var maxMoneyRobbed = function (nums) { - const dp = Array(nums.length).fill(0) - dp[0] = nums[0] - dp[1] = Math.max(nums[0], nums[1]) - - for (let i = 2; i < dp.length; i++) { - dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp.at(-1) -}; -``` - -## Go -```go -func rob(nums []int) int { - if len(nums) <= 2 { - return slices.Max(nums) - } - - return max( - maxMoneyRobbed(nums[1:]), - maxMoneyRobbed(nums[:len(nums) - 1]), - ) -} - -func maxMoneyRobbed(nums []int) int { - dp := make([]int, len(nums)) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i := 2; i < len(dp); i++ { - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/225-implement-stack-using-queues.md b/en/1-1000/225-implement-stack-using-queues.md deleted file mode 100644 index 66b9778..0000000 --- a/en/1-1000/225-implement-stack-using-queues.md +++ /dev/null @@ -1,709 +0,0 @@ -# 225. Implement Stack using Queues - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [225. Implement Stack using Queues - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/225-implement-stack-using-queues) for a better experience! - -LeetCode link: [225. Implement Stack using Queues](https://leetcode.com/problems/implement-stack-using-queues), difficulty: **Easy**. - -## LeetCode description of "225. Implement Stack using Queues" - -Implement a last-in-first-out (LIFO) stack using only two queues. The implemented stack should support all the functions of a normal stack (`push`, `top`, `pop`, and `empty`). - -Implement the `MyStack` class: - -- `void push(int x)` Pushes element `x` to the top of the stack. -- `int pop()` Removes the element on the top of the stack and returns it. -- `int top()` Returns the element on the top of the stack. -- `boolean empty()` Returns `true` if the stack is empty, `false` otherwise. - -**Notes**: - -- You must use **only** standard operations of a queue, which means that only `push to back`, `peek/pop from front`, `size` and `is empty` operations are valid. -- Depending on your language, the queue may not be supported natively. You may simulate a queue using a list or deque (double-ended queue) as long as you use only a queue's standard operations. - -### [Example 1] - -**Input**: `["MyStack", "push", "push", "top", "pop", "empty"] [[], [1], [2], [], [], []]` - -**Output**: `[null, null, null, 2, 2, false]` - -**Explanation**: - -

MyStack myStack = new MyStack();
-myStack.push(1);
-myStack.push(2);
-myStack.top(); // return 2
-myStack.pop(); // return 2
-myStack.empty(); // return False

- - -### [Constraints] - -- `1 <= x <= 9` -- At most `100` calls will be made to `push`, `pop`, `top`, and `empty`. -- All the calls to `pop` and `top` are valid. - -**Follow-up**: Can you implement the stack using only one queue? - -## Intuition 1 - -1. Two queues are used, one for input and output, and the other for temporary storage. -2. There are two options for using queues to simulate the functions of a stack: - 1. Option 1: Simplify the `pop()` and `top()` operations and complicate the `push(x)` operation. When `push(x)`, you need to insert `x` into the front of the queue with effort. - 2. Option 2: Simplify the `push(x)` operation and complicate the `pop()` and `top()` operations. When `pop()` or `top()`, you need to find the last data with effort. -3. Advantages of Option 1: Less code, because it only needs to complicate one method, while Solution 2 complicates two methods; easier to understand logically because it sorts the data in the queue according to the `last in, first out` rule. - -## Complexity - -- Time complexity: `push O(n), pop O(1), top O(1), empty O(1)`. -- Space complexity: `O(n)`. - -## Python - -```python -class MyStack: - def __init__(self): - self.queue = deque() - self.queue_temp = deque() - - def push(self, x: int) -> None: - # Move all 'queue' items to 'queue_temp'. - while self.queue: - self.queue_temp.append( - self.queue.popleft() - ) - - # Emplaced 'x' at the first of 'queue' because 'queue' is empty. - self.queue.append(x) - - # Move all 'queue_temp' items back to 'queue'. - while self.queue_temp: - self.queue.append( - self.queue_temp.popleft() - ) - - def pop(self) -> int: - return self.queue.popleft() - - def top(self) -> int: - return self.queue[0] - - def empty(self) -> bool: - return not self.queue -``` - -## C++ - -```cpp -class MyStack { -private: - queue queue_; - queue queue_temp_; - -public: - MyStack() {} - - void push(int x) { - // Step 1: Move all existing elements from main queue_ to temp_queue_ - while (!queue_.empty()) { - queue_temp_.push(queue_.front()); - queue_.pop(); - } - - // Step 2: Add the new element to the now-empty main queue_ - // This ensures the newest element is at the front (LIFO behavior) - queue_.push(x); - - // Step 3: Move all elements from temp_queue_ back to main queue_ - // This places all previous elements behind the new element - while (!queue_temp_.empty()) { - queue_.push(queue_temp_.front()); - queue_temp_.pop(); - } - } - - int pop() { - int val = queue_.front(); - queue_.pop(); - return val; - } - - int top() { return queue_.front(); } - - bool empty() { return queue_.empty(); } -}; -``` - -## Go - -```go -type MyStack struct { - // Main queue that stores elements in stack order - queue []int - // Temporary queue used during push operations - queueTemp []int -} - -func Constructor() MyStack { - return MyStack{ - queue: []int{}, - queueTemp: []int{}, - } -} - -func (this *MyStack) Push(x int) { - // Step 1: Move all existing elements from main queue to temp queue - for len(this.queue) > 0 { - // Remove from front and add to temp queue - this.queueTemp = append(this.queueTemp, this.queue[0]) - this.queue = this.queue[1:] - } - - // Step 2: Add the new element to the now-empty main queue - // This ensures the newest element is at the front (LIFO behavior) - this.queue = append(this.queue, x) - - // Step 3: Move all elements from temp queue back to main queue - // This places all previous elements behind the new element - for len(this.queueTemp) > 0 { - // Remove from front and add to main queue - this.queue = append(this.queue, this.queueTemp[0]) - this.queueTemp = this.queueTemp[1:] - } -} - -func (this *MyStack) Pop() int { - val := this.queue[0] - this.queue = this.queue[1:] - return val -} - -func (this *MyStack) Top() int { - return this.queue[0] -} - -func (this *MyStack) Empty() bool { - return len(this.queue) == 0 -} -``` - -## Ruby - -```ruby -class MyStack - def initialize - @queue = [] # Main queue that stores elements in stack order - @queue_temp = [] # Temporary queue used during push operations - end - - def push(x) - # Step 1: Move all existing elements from main queue to temp queue - while !@queue.empty? - @queue_temp.push(@queue.shift) - end - - # Step 2: Add the new element to the now-empty main queue - # This ensures the newest element is at the front (LIFO behavior) - @queue.push(x) - - # Step 3: Move all elements from temp queue back to main queue - # This places all previous elements behind the new element - while !@queue_temp.empty? - @queue.push(@queue_temp.shift) - end - end - - def pop - @queue.shift - end - - def top - @queue.first - end - - def empty - @queue.empty? - end -end -``` - -## JavaScript - -```javascript -var MyStack = function () { - this.queue = [] - this.queueTemp = [] -}; - -MyStack.prototype.push = function (x) { - while (this.queue.length > 0) { - this.queueTemp.push( - this.queue.shift() // remove from head - ) - } - - this.queue.push(x) - - while (this.queueTemp.length > 0) { - this.queue.push( - this.queueTemp.shift() // remove from head - ) - } -}; - -MyStack.prototype.pop = function () { - return this.queue.shift() // remove from head -}; - -MyStack.prototype.top = function () { - return this.queue[0] -}; - -MyStack.prototype.empty = function () { - return this.queue.length === 0 -}; -``` - -## Java - -```java -class MyStack { - private Queue queue; - private Queue queueTemp; - - public MyStack() { - queue = new LinkedList<>(); // main queue - queueTemp = new LinkedList<>(); - } - - public void push(int x) { - // Move all elements from main queue to temporary queue - while (!queue.isEmpty()) { - queueTemp.offer( - queue.poll() // Remove from front (standard queue operation) - ); - } - - // Add the new element to the now-empty main queue - // This will be the first element to be removed (stack's top) - queue.offer(x); - - // Move all elements back from temporary queue to main queue - // This ensures newest elements are at the front of the queue - while (!queueTemp.isEmpty()) { - queue.offer( - queueTemp.poll() // Remove from front (standard queue operation) - ); - } - } - - public int pop() { - return queue.poll(); - } - - public int top() { - return queue.peek(); - } - - public boolean empty() { - return queue.isEmpty(); - } -} -``` - -## C# - -```csharp -public class MyStack -{ - private Queue queue; // main queue - private Queue queueTemp; - - public MyStack() - { - queue = new Queue(); - queueTemp = new Queue(); - } - - public void Push(int x) - { - // Move all elements from main queue to temporary queue - while (queue.Count > 0) - { - queueTemp.Enqueue( - queue.Dequeue() - ); - } - - // Add the new element to the now-empty main queue - // This will be the first element to be removed (stack's top) - queue.Enqueue(x); - - // Move all elements back from temporary queue to main queue - // This ensures newest elements are at the front of the queue - while (queueTemp.Count > 0) - { - queue.Enqueue( - queueTemp.Dequeue() - ); - } - } - - public int Pop() - { - return queue.Dequeue(); - } - - public int Top() - { - return queue.Peek(); - } - - public bool Empty() - { - return queue.Count == 0; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -1. Two queues are used, one for input and output, and the other for temporary storage. -2. There are two options for using queues to simulate the functions of a stack: - 1. Option 1: Simplify the `pop()` and `top()` operations and complicate the `push(x)` operation. When `push(x)`, you need to insert `x` into the front of the queue with effort. - 2. Option 2: Simplify the `push(x)` operation and complicate the `pop()` and `top()` operations. When `pop()` or `top()`, you need to find the last data with effort. -3. This article mainly introduces `Option 2` to facilitate readers to compare the two solutions. - -## Complexity - -- Time complexity: `push O(1), pop O(n), top O(n), empty O(1)`. -- Space complexity: `O(n)`. - -## Python - -```python -class MyStack: - def __init__(self): - self.queue = deque() - self.queue_temp = deque() - - def push(self, x: int) -> None: - self.queue.append(x) - - def pop(self) -> int: - while len(self.queue) > 1: - self.queue_temp.append( - self.queue.popleft() - ) - - value = self.queue.popleft() - - while self.queue_temp: - self.queue.append( - self.queue_temp.popleft() - ) - - return value - - def top(self) -> int: - value = None - - while self.queue: - value = self.queue.popleft() - self.queue_temp.append(value) - - while self.queue_temp: - self.queue.append( - self.queue_temp.popleft() - ) - - return value - - def empty(self) -> bool: - return not self.queue -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 3 - -- You can use only one queue to make it. The only change is in the `push` method. Just find a way to insert `x` to the front of the queue without using another `queue_temp`. -- When implementing the `push` method, first `queue.push(x)`, so that `x` is inserted at the tail (back) of the queue, but we need to put `x` at the head (front) of the queue. -- Execute `queue.length - 1` times `queue.push(queue.pop())` to move all the data before `x` to the back of `x`. - -## Complexity - -- Time complexity: `push O(n), pop O(1), top O(1), empty O(1)`. -- Space complexity: `O(n)`. - -## JavaScript - -```javascript -var MyStack = function () { - this.queue = [] -}; - -MyStack.prototype.push = function (x) { - this.queue.push(x) - - _.times( - this.queue.length - 1, - () => this.queue.push(this.queue.shift()) - ) -}; - -MyStack.prototype.pop = function () { - return this.queue.shift() -}; - -MyStack.prototype.top = function () { - return this.queue[0] -}; - -MyStack.prototype.empty = function () { - return this.queue.length === 0 -}; -``` - -## Python - -```python -from collections import deque - - -class MyStack: - def __init__(self): - self.queue = deque() - - def push(self, x: int) -> None: - self.queue.append(x) - - # Rotate the queue to put the new element at the front - # This is done by moving all existing elements to the back - for _ in range(len(self.queue) - 1): - self.queue.append( - self.queue.popleft() - ) - - def pop(self) -> int: - return self.queue.popleft() - - def top(self) -> int: - return self.queue[0] - - def empty(self) -> bool: - return not self.queue -``` - -## C++ - -```cpp -class MyStack { -private: - queue q_; - -public: - MyStack() {} - - void push(int x) { - q_.push(x); - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for (int i = 0; i < q_.size() - 1; i++) { - q_.push(q_.front()); // Add front element to back - q_.pop(); // Remove from front - } - } - - int pop() { - int top = q_.front(); - q_.pop(); - return top; - } - - int top() { - return q_.front(); - } - - bool empty() { - return q_.empty(); - } -}; -``` - -## Go - -```go -type MyStack struct { - queue []int -} - -func Constructor() MyStack { - return MyStack{ - queue: make([]int, 0), - } -} - -func (this *MyStack) Push(x int) { - // Add the new element to the queue - this.queue = append(this.queue, x) - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for i := 0; i < len(this.queue) - 1; i++ { - // Move first element to the back - this.queue = append(this.queue, this.queue[0]) - this.queue = this.queue[1:] - } -} - -func (this *MyStack) Pop() int { - // Remove and return the first element (stack's top) - top := this.queue[0] - this.queue = this.queue[1:] - return top -} - -func (this *MyStack) Top() int { - return this.queue[0] -} - -func (this *MyStack) Empty() bool { - return len(this.queue) == 0 -} -``` - -## Ruby - -```ruby -class MyStack - def initialize - @queue = [] - end - - def push(x) - @queue.push(x) - - # Rotate the queue to put the new element at the front - # This is done by moving all existing elements to the back - (@queue.length - 1).times do - @queue.push(@queue.shift) # Move first element to the back - end - end - - def pop - @queue.shift - end - - def top - @queue.first - end - - def empty - @queue.empty? - end -end -``` - -## Java - -```java -import java.util.LinkedList; -import java.util.Queue; - -class MyStack { - private Queue queue; - - public MyStack() { - queue = new LinkedList<>(); - } - - public void push(int x) { - queue.offer(x); - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for (int i = 0; i < queue.size() - 1; i++) { - queue.offer(queue.poll()); // Move first element to the back - } - } - - public int pop() { - return queue.poll(); - } - - public int top() { - return queue.peek(); - } - - public boolean empty() { - return queue.isEmpty(); - } -} -``` - -## C# - -```csharp -using System.Collections.Generic; - -public class MyStack -{ - private Queue queue; - - public MyStack() - { - queue = new Queue(); - } - - public void Push(int x) - { - queue.Enqueue(x); - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for (int i = 0; i < queue.Count - 1; i++) - { - queue.Enqueue(queue.Dequeue()); // Move first element to the back - } - } - - public int Pop() - { - return queue.Dequeue(); - } - - public int Top() - { - return queue.Peek(); - } - - public bool Empty() - { - return queue.Count == 0; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [225. Implement Stack using Queues - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/225-implement-stack-using-queues). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/232-implement-queue-using-stacks.md b/en/1-1000/232-implement-queue-using-stacks.md deleted file mode 100644 index 05fb864..0000000 --- a/en/1-1000/232-implement-queue-using-stacks.md +++ /dev/null @@ -1,356 +0,0 @@ -# 232. Implement Queue using Stacks - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [232. Implement Queue using Stacks - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/232-implement-queue-using-stacks) for a better experience! - -LeetCode link: [232. Implement Queue using Stacks](https://leetcode.com/problems/implement-queue-using-stacks), difficulty: **Easy**. - -## LeetCode description of "232. Implement Queue using Stacks" - -Implement a first in first out (FIFO) queue using only two stacks. The implemented queue should support all the functions of a normal queue (`push`, `peek`, `pop`, and `empty`). - -Implement the `MyQueue` class: - -- `void push(int x)` Pushes element x to the back of the queue. -- `int pop()` Removes the element from the front of the queue and returns it. -- `int peek()` Returns the element at the front of the queue. -- `boolean empty()` Returns `true` if the queue is empty, `false` otherwise. - -**Notes:** - -- You must use **only** standard operations of a stack, which means only `push to top`, `peek/pop from top`, `size`, and `is empty` operations are valid. -- Depending on your language, the stack may not be supported natively. You may simulate a stack using a list or deque (double-ended queue) as long as you use only a stack's standard operations. - -### [Example 1] - -**Input**: `["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []]` - -**Output**: `[null, null, null, 1, 1, false]` - -**Explanation**: - -

MyQueue myQueue = new MyQueue();
-myQueue.push(1); // queue is: [1]
-myQueue.push(2); // queue is: 1, 2
-myQueue.peek(); // return 1
-myQueue.pop(); // return 1, queue is [2]
-myQueue.empty(); // return false

- - -### [Constraints] - -- `1 <= x <= 9` -- At most `100` calls will be made to `push`, `pop`, `peek`, and `empty`. -- All the calls to `pop` and `peek` are valid. - - -**Follow-up**: Can you implement the queue such that each operation is amortized `O(1)` time complexity? In other words, performing `n` operations will take overall `O(n)` time even if one of those operations may take longer. - -## Intuition - -- To implement a queue with two stacks, the intuitive idea is that one stack `stack_in` is dedicated to `push`, and the other stack `stack_out` is dedicated to `pop`. - -- `Push` can be easy, just `push` directly, then `pop` is not so easy. How to do it? -
Click to view the answer

Stack is last in first out, queue is first in first out, the two are opposite, so it is not possible to `pop` directly from `stack_in`. You have to add the elements in `stack_in` to `stack_out` in reverse, and then `pop`.

- -## Complexity - -> `pop` and `peek` appear to be `O(n)`, but they are actually `O(1)`. This is because if `dump_into_stack_out` operates on `m` numbers at a time, then each `pop` operation for the next `m` times is `O(1)`. - -- Time complexity: `push O(1), pop O(1), peek O(1), empty O(1)`. -- Space complexity: `O(n)`. - -## Python - -```python -class MyQueue: - def __init__(self): - self.stack_in = [] - self.stack_out = [] - - def push(self, x: int) -> None: - self.stack_in.append(x) - - def pop(self) -> int: - self.dump_into_stack_out_if_it_is_empty() - return self.stack_out.pop() - - def peek(self) -> int: - self.dump_into_stack_out_if_it_is_empty() - return self.stack_out[-1] - - def empty(self) -> bool: - return not self.stack_out and not self.stack_in - - def dump_into_stack_out_if_it_is_empty(self) -> int: - if not self.stack_out: - while self.stack_in: - self.stack_out.append(self.stack_in.pop()) -``` - -## JavaScript - -```javascript -var MyQueue = function () { - this.stackIn = [] - this.stackOut = [] -}; - -MyQueue.prototype.push = function (x) { - this.stackIn.push(x) -}; - -MyQueue.prototype.pop = function () { - this.dumpIntoStackOutWhenItIsEmpty() - return this.stackOut.pop() -}; - -MyQueue.prototype.peek = function () { - this.dumpIntoStackOutWhenItIsEmpty() - return this.stackOut.at(-1) -}; - -MyQueue.prototype.empty = function () { - return this.stackOut.length === 0 && this.stackIn.length === 0 -}; - -MyQueue.prototype.dumpIntoStackOutWhenItIsEmpty = function () { - if (this.stackOut.length === 0) { - while (this.stackIn.length > 0) { - this.stackOut.push(this.stackIn.pop()) - } - } -} -``` - -## Java - -```java -import java.util.Stack; - -class MyQueue { - private Stack stackIn; - private Stack stackOut; - - public MyQueue() { - stackIn = new Stack<>(); - stackOut = new Stack<>(); - } - - public void push(int x) { - stackIn.push(x); - } - - public int pop() { - dumpIntoStackOutWhenItIsEmpty(); - return stackOut.pop(); - } - - public int peek() { - dumpIntoStackOutWhenItIsEmpty(); - return stackOut.peek(); - } - - public boolean empty() { - return stackIn.empty() && stackOut.empty(); - } - - private void dumpIntoStackOutWhenItIsEmpty() { - if (stackOut.empty()) { - while (!stackIn.empty()) { - stackOut.push(stackIn.pop()); - } - } - } -} -``` - -## C++ - -```cpp -class MyQueue { -private: - stack stack_in_; - stack stack_out_; - - void dumpIntoStackOutWhenItIsEmpty() { - if (stack_out_.empty()) { - while (!stack_in_.empty()) { - stack_out_.push(stack_in_.top()); - stack_in_.pop(); - } - } - } - -public: - MyQueue() {} - - void push(int x) { - stack_in_.push(x); - } - - int pop() { - dumpIntoStackOutWhenItIsEmpty(); - int value = stack_out_.top(); - stack_out_.pop(); - return value; - } - - int peek() { - dumpIntoStackOutWhenItIsEmpty(); - return stack_out_.top(); - } - - bool empty() { - return stack_in_.empty() && stack_out_.empty(); - } -}; -``` - -## C# - -```csharp -using System.Collections.Generic; - -public class MyQueue -{ - private Stack stackIn; - private Stack stackOut; - - public MyQueue() - { - stackIn = new Stack(); - stackOut = new Stack(); - } - - public void Push(int x) - { - stackIn.Push(x); - } - - public int Pop() - { - DumpIntoStackOutWhenItIsEmpty(); - return stackOut.Pop(); - } - - public int Peek() - { - DumpIntoStackOutWhenItIsEmpty(); - return stackOut.Peek(); - } - - public bool Empty() - { - return stackIn.Count == 0 && stackOut.Count == 0; - } - - private void DumpIntoStackOutWhenItIsEmpty() - { - if (stackOut.Count == 0) - { - while (stackIn.Count > 0) - { - stackOut.Push(stackIn.Pop()); - } - } - } -} -``` - -## Go - -```go -type MyQueue struct { - stackIn []int - stackOut []int -} - -func Constructor() MyQueue { - return MyQueue{ - stackIn: make([]int, 0), - stackOut: make([]int, 0), - } -} - -func (this *MyQueue) Push(x int) { - this.stackIn = append(this.stackIn, x) -} - -func (this *MyQueue) Pop() int { - this.dumpIntoStackOutWhenItIsEmpty() - top := this.stackOut[len(this.stackOut) - 1] - this.stackOut = this.stackOut[:len(this.stackOut) - 1] - return top -} - -func (this *MyQueue) Peek() int { - this.dumpIntoStackOutWhenItIsEmpty() - return this.stackOut[len(this.stackOut) - 1] -} - -func (this *MyQueue) Empty() bool { - return len(this.stackIn) == 0 && len(this.stackOut) == 0 -} - -func (this *MyQueue) dumpIntoStackOutWhenItIsEmpty() { - if len(this.stackOut) == 0 { - for len(this.stackIn) > 0 { - top := this.stackIn[len(this.stackIn) - 1] - this.stackIn = this.stackIn[:len(this.stackIn) - 1] - this.stackOut = append(this.stackOut, top) - } - } -} -``` - -## Ruby - -```ruby -class MyQueue - def initialize - @stack_in = [] - @stack_out = [] - end - - def push(x) - @stack_in.push(x) - end - - def pop - dump_into_stack_out_when_it_is_empty - @stack_out.pop - end - - def peek - dump_into_stack_out_when_it_is_empty - @stack_out.last - end - - def empty - @stack_in.empty? && @stack_out.empty? - end - - private - - def dump_into_stack_out_when_it_is_empty - if @stack_out.empty? - while !@stack_in.empty? - @stack_out.push(@stack_in.pop) - end - end - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [232. Implement Queue using Stacks - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/232-implement-queue-using-stacks). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/238-product-of-array-except-self.md b/en/1-1000/238-product-of-array-except-self.md deleted file mode 100644 index 81fe365..0000000 --- a/en/1-1000/238-product-of-array-except-self.md +++ /dev/null @@ -1,551 +0,0 @@ -# 238. Product of Array Except Self - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [238. Product of Array Except Self - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/238-product-of-array-except-self) for a better experience! - -LeetCode link: [238. Product of Array Except Self](https://leetcode.com/problems/product-of-array-except-self), difficulty: **Medium**. - -## LeetCode description of "238. Product of Array Except Self" - -Given an integer array `nums`, return an array `answer` such that `answer[i]` is equal to the product of all the elements of `nums` except `nums[i]`. - -The product of any prefix or suffix of `nums` is **guaranteed** to fit in a **32-bit** integer. - -You must write an algorithm that runs in `O(n)` time and **without using the division operation**. - -### [Example 1] - -**Input**: `nums = [1,2,3,4]` - -**Output**: `[24,12,8,6]` - -### [Example 2] - -**Input**: `nums = [-1,1,0,-3,3]` - -**Output**: `[0,0,9,0,0]` - -### [Constraints] - -- `2 <= nums.length <= 10^5` -- `-30 <= nums[i] <= 30` -- The input is generated such that `answer[i]` is **guaranteed** to fit in a **32-bit** integer. - - -**Follow up**: Can you solve the problem in `O(1)` extra space complexity? (The output array **does not** count as extra space for space complexity analysis.) - -### [Hints] - -
- Hint 1 - Think how you can efficiently utilize prefix and suffix products to calculate the product of all elements except self for each index. Can you pre-compute the prefix and suffix products in linear time to avoid redundant calculations? - - - -
- -
- Hint 2 - Can you minimize additional space usage by reusing memory or modifying the input array to store intermediate results? - - -
- -## Intuition 1 - -1. **Decompose the Problem**: Break down the `product except self` into `left product × right product` -2. **Two Passes**: - - First pass: Calculate the left product for each element - - Second pass: Calculate the right product for each element -3. **Combine Results**: Multiply left and right products to get the final result - -## Pattern of "Pre-Computation Techniques" - -**Pre-Computation Techniques** are an optimization method that reduces real-time computational overhead by calculating and storing intermediate or frequently used data in advance. The core idea is **"trade space for time."** - -#### Key Application Scenarios - -- **Prefix/Suffix computation problems** for arrays. -- **High-frequency computation problems**: Such as Fibonacci sequences, factorials, prime number tables, etc., which avoid repetitive calculations by pre-generating lookup tables. -- **Dynamic Programming (DP)**: Pre-computing and storing solutions to sub-problems, e.g., the `knapsack problem` or `shortest path problems`. - -## Step by Step Solutions - -1. **Initialize Arrays**: - - Create a `leftProducts` array to store the product of all elements to the left of each element - - Create a `rightProducts` array to store the product of all elements to the right of each element - -2. **Compute Left Products** (Left to Right Pass): - - The left product of the first element is initialized to `1` - - For subsequent elements: `leftProducts[i] = nums[i-1] * leftProducts[i-1]` - -3. **Compute Right Products** (Right to Left Pass): - - The right product of the last element is initialized to `1` - - For previous elements: `rightProducts[i] = nums[i+1] * rightProducts[i+1]` - -4. **Combine Results**: - - For each position, multiply left and right products: `answer[i] = leftProducts[i] * rightProducts[i]` - -5. **Return the Result Array** - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer[]} -def product_except_self(nums) - # nums: [1, 2, 3, 4] - # left_products: [1, 1, 2, 6] - # right_products: [24,12, 4, 1] - # answer: [24,12, 8, 6] - size = nums.size - - left_products = Array.new(size, 1) - (1...size).each do |i| - left_products[i] = nums[i - 1] * left_products[i - 1] - end - - right_products = Array.new(size, 1) - (size - 2).downto(0) do |i| - right_products[i] = nums[i + 1] * right_products[i + 1] - end - - answer = [] - (0...size).each do |i| - answer << left_products[i] * right_products[i] - end - - answer -end -``` - -## Python - -```python -class Solution: - def productExceptSelf(self, nums: List[int]) -> List[int]: - size = len(nums) - - # nums: [1, 2, 3, 4] - # left_products: [1, 1, 2, 6] - # right_products: [24,12, 4, 1] - # answer: [24,12, 8, 6] - left_products = [1] * size - for i in range(1, size): - left_products[i] = nums[i - 1] * left_products[i - 1] - - right_products = [1] * size - for i in range(size - 2, -1, -1): - right_products[i] = nums[i + 1] * right_products[i + 1] - - answer = [] - for i in range(size): - answer.append(left_products[i] * right_products[i]) - - return answer -``` - -## Java - -```java -class Solution { - public int[] productExceptSelf(int[] nums) { - int size = nums.length; - // nums: [1, 2, 3, 4] - // left_products: [1, 1, 2, 6] - // right_products: [24,12, 4, 1] - // answer: [24,12, 8, 6] - int[] leftProducts = new int[size]; - leftProducts[0] = 1; - for (int i = 1; i < size; i++) { - leftProducts[i] = nums[i - 1] * leftProducts[i - 1]; - } - - int[] rightProducts = new int[size]; - rightProducts[size - 1] = 1; - for (int i = size - 2; i >= 0; i--) { - rightProducts[i] = nums[i + 1] * rightProducts[i + 1]; - } - - int[] answer = new int[size]; - for (int i = 0; i < size; i++) { - answer[i] = leftProducts[i] * rightProducts[i]; - } - - return answer; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector productExceptSelf(vector& nums) { - int size = nums.size(); - // nums: [1, 2, 3, 4] - // left_products: [1, 1, 2, 6] - // right_products: [24,12, 4, 1] - // answer: [24,12, 8, 6] - vector left_products(size, 1); - for (int i = 1; i < size; i++) { - left_products[i] = nums[i - 1] * left_products[i - 1]; - } - - vector right_products(size, 1); - for (int i = size - 2; i >= 0; i--) { - right_products[i] = nums[i + 1] * right_products[i + 1]; - } - - vector answer(size); - for (int i = 0; i < size; i++) { - answer[i] = left_products[i] * right_products[i]; - } - - return answer; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number[]} - */ -var productExceptSelf = function(nums) { - const size = nums.length - - const leftProducts = new Array(size).fill(1) - for (let i = 1; i < size; i++) { - leftProducts[i] = nums[i - 1] * leftProducts[i - 1] - } - - const rightProducts = new Array(size).fill(1) - for (let i = size - 2; i >= 0; i--) { - rightProducts[i] = nums[i + 1] * rightProducts[i + 1] - } - - const answer = [] - for (let i = 0; i < size; i++) { - answer.push(leftProducts[i] * rightProducts[i]) - } - - return answer -}; - -``` - -## C# - -```csharp -public class Solution -{ - public int[] ProductExceptSelf(int[] nums) - { - int size = nums.Length; - // nums: [1, 2, 3, 4] - // left_products: [1, 1, 2, 6] - // right_products: [24,12, 4, 1] - // answer: [24,12, 8, 6] - int[] leftProducts = new int[size]; - leftProducts[0] = 1; - - for (int i = 1; i < size; i++) - leftProducts[i] = nums[i - 1] * leftProducts[i - 1]; - - int[] rightProducts = new int[size]; - rightProducts[size - 1] = 1; - - for (int i = size - 2; i >= 0; i--) - rightProducts[i] = nums[i + 1] * rightProducts[i + 1]; - - int[] answer = new int[size]; - - for (int i = 0; i < size; i++) - answer[i] = leftProducts[i] * rightProducts[i]; - - return answer; - } -} -``` - -## Go - -```go -func productExceptSelf(nums []int) []int { - size := len(nums) - - leftProducts := make([]int, size) - leftProducts[0] = 1 - for i := 1; i < size; i++ { - leftProducts[i] = nums[i - 1] * leftProducts[i - 1] - } - - rightProducts := make([]int, size) - rightProducts[size - 1] = 1 - for i := size - 2; i >= 0; i-- { - rightProducts[i] = nums[i + 1] * rightProducts[i + 1] - } - - answer := make([]int, size) - for i := 0; i < size; i++ { - answer[i] = leftProducts[i] * rightProducts[i] - } - - return answer -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -1. **Space Optimization**: Utilize the output array to store intermediate results, avoiding extra space -2. **Two-Phase Calculation**: First compute left products and store in the result, then dynamically compute right products and merge directly -3. **In-Place Operation**: Use only a single variable to dynamically maintain the right product - -## Step by Step Solutions - -1. **Initialize Result Array**: - - Create an `answer` array of the same size, initialized with all 1s - -2. **Compute Left Products** (Left → Right Pass): - - Initialize `left_product = 1` - - During traversal: `answer[i] = left_product`, then `left_product *= nums[i]` - -3. **Compute Right Products and Merge** (Right → Left Pass): - - Initialize `right_product = 1` - - During traversal: `answer[i] *= right_product`, then `right_product *= nums[i]` - -4. **Return Result Array** - - Space Complexity: O(1) (Output array not counted in space complexity) - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer[]} -def product_except_self(nums) - size = nums.size - answer = Array.new(size, 1) - - left_product = 1 - (0...size).each do |i| - answer[i] = left_product - left_product *= nums[i] - end - - # nums: [1, 2, 3, 4] - # answer: [1, 1, 2, 6] left_product done - # answer: [24,12, 8, 6] right_product done - - right_product = 1 - (size - 1).downto(0) do |i| - answer[i] *= right_product - right_product *= nums[i] - end - - answer -end -``` - -## Python - -```python -class Solution: - def productExceptSelf(self, nums: List[int]) -> List[int]: - size = len(nums) - answer = [1] * size - - left_product = 1 - for i in range(size): - answer[i] = left_product - left_product *= nums[i] - - # nums: [1, 2, 3, 4] - # answer: [1, 1, 2, 6] left_product done - # answer: [24,12, 8, 6] right_product done - - right_product = 1 - for i in range(size-1, -1, -1): - answer[i] *= right_product - right_product *= nums[i] - - return answer -``` - -## Java - -```java -class Solution { - public int[] productExceptSelf(int[] nums) { - int size = nums.length; - int[] answer = new int[size]; - Arrays.fill(answer, 1); - - int leftProduct = 1; - for (int i = 0; i < size; i++) { - answer[i] = leftProduct; - leftProduct *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] leftProduct done - // answer: [24,12, 8, 6] rightProduct done - - int rightProduct = 1; - for (int i = size - 1; i >= 0; i--) { - answer[i] *= rightProduct; - rightProduct *= nums[i]; - } - - return answer; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector productExceptSelf(vector& nums) { - int size = nums.size(); - vector answer(size, 1); - - int left_product = 1; - for (int i = 0; i < size; ++i) { - answer[i] = left_product; - left_product *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] left_product done - // answer: [24,12, 8, 6] right_product done - - int right_product = 1; - for (int i = size - 1; i >= 0; --i) { - answer[i] *= right_product; - right_product *= nums[i]; - } - - return answer; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number[]} - */ -var productExceptSelf = function(nums) { - const answer = []; - let left_product = 1; - - for (let i = 0; i < nums.length; i++) { - answer[i] = left_product; - left_product *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] left_product done - // answer: [24,12, 8, 6] right_product done - - right_product = 1; - - for (let i = nums.length - 1; i >= 0; i--) { - answer[i] *= right_product; - right_product *= nums[i]; - } - - return answer; -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] ProductExceptSelf(int[] nums) - { - int size = nums.Length; - int[] answer = new int[size]; - Array.Fill(answer, 1); - - int leftProduct = 1; - for (int i = 0; i < size; i++) - { - answer[i] = leftProduct; - leftProduct *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] leftProduct done - // answer: [24,12, 8, 6] rightProduct done - - int rightProduct = 1; - for (int i = size - 1; i >= 0; i--) - { - answer[i] *= rightProduct; - rightProduct *= nums[i]; - } - - return answer; - } -} -``` - -## Go - -```go -func productExceptSelf(nums []int) []int { - n := len(nums) - answer := make([]int, n) - - answer[0] = 1 - for i := 1; i < n; i++ { - answer[i] = answer[i-1] * nums[i-1] - } - - right := 1 - for i := n - 1; i >= 0; i-- { - answer[i] *= right - right *= nums[i] - } - - return answer -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [238. Product of Array Except Self - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/238-product-of-array-except-self). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/24-swap-nodes-in-pairs.md b/en/1-1000/24-swap-nodes-in-pairs.md deleted file mode 100644 index 58146b8..0000000 --- a/en/1-1000/24-swap-nodes-in-pairs.md +++ /dev/null @@ -1,378 +0,0 @@ -# 24. Swap Nodes in Pairs - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [24. Swap Nodes in Pairs - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/24-swap-nodes-in-pairs) for a better experience! - -LeetCode link: [24. Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs), difficulty: **Medium**. - -## LeetCode description of "24. Swap Nodes in Pairs" - -Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list's nodes (i.e., only nodes themselves may be changed.) - -### [Example 1] - -![](../../images/examples/24_1.jpg) - -**Input**: `head = [1,2,3,4]` - -**Output**: `[2,1,4,3]` - -### [Example 2] - -**Input**: `head = []` - -**Output**: `[]` - -### [Example 3] - -**Input**: `head = [1]` - -**Output**: `[1]` - -### [Example 4] - -**Input**: `head = [1,2,3]` - -**Output**: `[2,1,3]` - -### [Constraints] - -- The number of nodes in the list is in the range `[0, 100]`. -- `0 <= Node.val <= 100` - -## Intuition - -Before solving this problem, it is recommended to solve the simple problem [206. Reverse Linked List](206-reverse-linked-list.md) first. - -1. To solve this problem, you still need to define at least two variables: `current` and `previous`. -2. The loop condition should be `while (current.next != null)` instead of `while (current != null)`, because the operations that need to be performed include `current.next.next`. - -## Step by Step Solutions - -1. Traverse all nodes. - - ```java - var previous = null; - var current = head; - - while (current != null) { - current = current.next; - } - ``` - -2. Because every two nodes swap positions, it is necessary to change it to taking two steps at a time. - - ```java - var previous = null; - var current = head; - - while (current != null && current.next != null) { // 1 - var nextNext = current.next.next; // 2 - current = nextNext; // 3 - } - ``` - -3. Swap the positions of `current` and `current.next`. - - ```java - var previous = null; - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - current.next.next = current; // 1 - current.next = nextNext; // 2 - - current = nextNext; - } - ``` - -4. Process `previous`. - - ```java - var previous = null; - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - previous.next = current.next; // 1 - current.next.next = current; - current.next = nextNext; - - previous = current; // 2 - current = nextNext; - } - ``` - -5. Determine the return value. Because the `head` node will be swapped to the second node when the number of nodes exceeds 1, it is best to add a `dummy_head` node for unified and convenient processing. - - ```java - var dummyHead = new ListNode(); // 1 - dummyHead.next = head; // 2 - - var previous = dummyHead; // 3 - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - previous.next = current.next; - current.next.next = current; - current.next = nextNext; - - previous = current; - current = nextNext; - } - - return dummyHead.next; // 4 - ``` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ - -class Solution { - public ListNode swapPairs(ListNode head) { - var dummyHead = new ListNode(0, head); - var previous = dummyHead; - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - previous.next = current.next; - current.next.next = current; - current.next = nextNext; - - previous = current; - current = nextNext; - } - - return dummyHead.next; - } -} -``` - -## Python - -```python -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: - dummy_head = ListNode(next=head) - previous = dummy_head - current = head - - while current and current.next: - next_next = current.next.next - - previous.next = current.next - current.next.next = current - current.next = next_next - - previous = current - current = next_next - - return dummy_head.next -``` - -## C++ - -```cpp -/** - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* swapPairs(ListNode* head) { - auto dummy_head = new ListNode(0, head); - auto previous = dummy_head; - auto current = head; - - while (current != nullptr && current->next != nullptr) { - auto next_next = current->next->next; - - previous->next = current->next; - current->next->next = current; - current->next = next_next; - - previous = current; - current = next_next; - } - - auto result = dummy_head->next; - delete dummy_head; - return result; - } -}; -``` - -## JavaScript - -```javascript -/** - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var swapPairs = function (head) { - const dummyHead = new ListNode(0, head) - - let previous = dummyHead - let current = head - - while (current != null && current.next != null) { - const nextNext = current.next.next - - previous.next = current.next - current.next.next = current - current.next = nextNext - - previous = current - current = nextNext - } - - return dummyHead.next -}; -``` - -## C# - -```csharp -/** - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution -{ - public ListNode SwapPairs(ListNode head) - { - var dummyHead = new ListNode(0, head); - var previous = dummyHead; - var current = head; - - while (current != null && current.next != null) - { - var nextNext = current.next.next; - - previous.next = current.next; - current.next.next = current; - current.next = nextNext; - - previous = current; - current = nextNext; - } - - return dummyHead.next; - } -} -``` - -## Go - -```go -/** - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func swapPairs(head *ListNode) *ListNode { - dummyHead := &ListNode{0, head} - - previous := dummyHead - current := head - - for current != nil && current.Next != nil { - nextNext := current.Next.Next - - previous.Next = current.Next - current.Next.Next = current - current.Next = nextNext - - previous = current - current = nextNext - } - - return dummyHead.Next -} -``` - -## Ruby - -```ruby -# class ListNode -# attr_accessor :val, :next -# -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def swap_pairs(head) - dummy_head = ListNode.new - dummy_head.next = head - - previous = dummy_head - current = head - - while current && current.next - next_next = current.next.next - - previous.next = current.next - current.next.next = current - current.next = next_next - - previous = current - current = next_next - end - - dummy_head.next -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [24. Swap Nodes in Pairs - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/24-swap-nodes-in-pairs). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/242-valid-anagram.md b/en/1-1000/242-valid-anagram.md deleted file mode 100644 index 048ce89..0000000 --- a/en/1-1000/242-valid-anagram.md +++ /dev/null @@ -1,223 +0,0 @@ -# 242. Valid Anagram - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [242. Valid Anagram - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/242-valid-anagram) for a better experience! - -LeetCode link: [242. Valid Anagram](https://leetcode.com/problems/valid-anagram), difficulty: **Easy**. - -## LeetCode description of "242. Valid Anagram" - -Given two strings `s` and `t`, return `true` if `t` is an **anagram** of `s`, and `false` otherwise. - -> An **anagram** is a word or phrase formed by rearranging the letters of a different word or phrase, using all the original letters exactly once. - -### [Example 1] - -**Input**: `s = "anagram", t = "nagaram"` - -**Output**: `true` - -### [Example 2] - -**Input**: `s = "rat", t = "car"` - -**Output**: `false` - -### [Constraints] - -- `1 <= s.length, t.length <= 5 * 10^4` -- `s` and `t` consist of lowercase English letters. - -## Intuition - -1. If the lengths of the two strings are different, return `false` directly. -2. Use two `hash tables` to store the statistics of the two strings respectively, with the `key` being the character and the `value` being the number of characters. -3. Compare the two `hash tables` to see if they are equal. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public boolean isAnagram(String s, String t) { - if (s.length() != t.length()) { - return false; - } - - var sCharToCount = new HashMap(); - for (var character : s.toCharArray()) { - sCharToCount.put(character, sCharToCount.getOrDefault(character, 0) + 1); - } - - var tCharToCount = new HashMap(); - for (var character : t.toCharArray()) { - tCharToCount.put(character, tCharToCount.getOrDefault(character, 0) + 1); - } - - return sCharToCount.equals(tCharToCount); - } -} -``` - -## Python - -```python -# from collections import defaultdict - -class Solution: - def isAnagram(self, s: str, t: str) -> bool: - if len(s) != len(t): - return False - - s_char_to_count = defaultdict(int) - for char in s: - s_char_to_count[char] += 1 - - t_char_to_count = defaultdict(int) - for char in t: - t_char_to_count[char] += 1 - - return s_char_to_count == t_char_to_count -``` - -## JavaScript - -```javascript -var isAnagram = function (s, t) { - if (s.length != t.length) { - return false; - } - - const sCharToCount = new Map() - const tCharToCount = new Map() - - for (const char of s) { - sCharToCount.set(char, (sCharToCount.get(char) || 0) + 1) - } - - for (const char of t) { - tCharToCount.set(char, (tCharToCount.get(char) || 0) + 1) - } - - return _.isEqual(sCharToCount, tCharToCount) -}; -``` - -## C# - -```csharp -public class Solution -{ - public bool IsAnagram(string s, string t) - { - if (s.Length != t.Length) - return false; - - var sCharToCount = new Dictionary(); - var tCharToCount = new Dictionary(); - - foreach (char character in s) - sCharToCount[character] = sCharToCount.GetValueOrDefault(character, 0) + 1; - - foreach (char character in t) - tCharToCount[character] = tCharToCount.GetValueOrDefault(character, 0) + 1; - - foreach (var entry in sCharToCount) - { - if (entry.Value != tCharToCount.GetValueOrDefault(entry.Key)) - { - return false; - } - } - - return true; - } -} -``` - -## Go - -```go -import "reflect" - -func isAnagram(s string, t string) bool { - if len(s) != len(t) { - return false - } - - // Create frequency maps for both strings - sCharCount := make(map[rune]int) - for _, char := range s { - sCharCount[char]++ - } - - tCharCount := make(map[rune]int) - for _, char := range t { - tCharCount[char]++ - } - - return reflect.DeepEqual(sCharCount, tCharCount) -} -``` - -## Ruby - -```ruby -def is_anagram(s, t) - return false if s.length != t.length - - s_char_to_count = Hash.new(0) - t_char_to_count = Hash.new(0) - - s.each_char do |char| - s_char_to_count[char] += 1 - end - - t.each_char do |char| - t_char_to_count[char] += 1 - end - - s_char_to_count == t_char_to_count -end -``` - -## C++ - -```cpp -class Solution { -public: - bool isAnagram(string s, string t) { - if (s.length() != t.length()) { - return false; - } - - unordered_map s_char_to_count; - for (char character : s) { - s_char_to_count[character]++; - } - - unordered_map t_char_to_count; - for (char character : t) { - t_char_to_count[character]++; - } - - return s_char_to_count == t_char_to_count; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [242. Valid Anagram - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/242-valid-anagram). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/27-remove-element.md b/en/1-1000/27-remove-element.md deleted file mode 100644 index 82e7a28..0000000 --- a/en/1-1000/27-remove-element.md +++ /dev/null @@ -1,436 +0,0 @@ -# 27. Remove Element - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [27. Remove Element - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/27-remove-element) for a better experience! - -LeetCode link: [27. Remove Element](https://leetcode.com/problems/remove-element), difficulty: **Easy**. - -## LeetCode description of "27. Remove Element" - -Given an integer array `nums` and an integer `val`, remove all occurrences of `val` in `nums` [in-place](https://en.wikipedia.org/wiki/In-place_algorithm). The order of the elements may be changed. Then return *the number of elements in `nums` which are not equal to `val`*. - -Consider the number of elements in `nums` which are not equal to `val` be `k`, to get accepted, you need to do the following things: - -- Change the array `nums` such that the first `k` elements of `nums` contain the elements which are not equal to `val`. The remaining elements of `nums` are not important as well as the size of `nums`. -- Return `k`. - -### [Example 1] - -**Input**: `nums = [3,2,2,3], val = 3` - -**Output**: `2, nums = [2,2,_,_]` - -**Explanation**: - -

Your function should return k = 2, with the first two elements of nums being 2.
-It does not matter what you leave beyond the returned k (hence they are underscores).

- - -### [Example 2] - -**Input**: `nums = [0,1,2,2,3,0,4,2], val = 2` - -**Output**: `5, nums = [0,1,4,0,3,_,_,_]` - -**Explanation**: - -

Your function should return k = 5, with the first five elements of nums containing 0, 0, 1, 3, and 4.
-Note that the five elements can be returned in any order.
-It does not matter what you leave beyond the returned k (hence they are underscores).

- - -### [Constraints] - -- `0 <= nums.length <= 100` -- `0 <= nums[i] <= 50` -- `0 <= val <= 100` - -### [Hints] - -
- Hint 1 - The problem statement clearly asks us to modify the array in-place and it also says that the element beyond the new length of the array can be anything. Given an element, we need to remove all the occurrences of it from the array. We don't technically need to **remove** that element per-say, right? - - -
- -
- Hint 2 - We can move all the occurrences of this element to the end of the array. Use two pointers! - - ![](../../images/hints/27_2.png) -
- -
- Hint 3 - Yet another direction of thought is to consider the elements to be removed as non-existent. In a single pass, if we keep copying the visible elements in-place, that should also solve this problem for us. - - -
- -## Intuition 1 - -- `Two pointers`, one on the left and one on the right. The left one points to the head of the array, and the right one points to the tail of the array. -- If the value pointed by the left pointer is found to be equal to **val**, and the value pointed by the right pointer is not equal to *val*, then swap the two the values. -- This method is easy to think of, but the amount of code is more than the `fast and slow pointers`. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -class Solution { - public int removeElement(int[] nums, int val) { - var left = 0; - var right = nums.length - 1; - - while (left <= right) { - if (nums[left] != val) { - left += 1; - continue; - } - - if (nums[right] == val) { - right -= 1; - continue; - } - - nums[left] = nums[right]; - left += 1; - right -= 1; - } - - return left; - } -} -``` - -## Python - -```python -class Solution: - def removeElement(self, nums: List[int], val: int) -> int: - left = 0 - right = len(nums) - 1 - - while left <= right: - if nums[left] != val: - left += 1 - continue - - if nums[right] == val: - right -= 1 - continue - - nums[left] = nums[right] - left += 1 - right -= 1 - - return left -``` - -## C++ - -```cpp -class Solution { -public: - int removeElement(vector& nums, int val) { - int left = 0; - int right = nums.size() - 1; - - while (left <= right) { - if (nums[left] != val) { - left += 1; - continue; - } - - if (nums[right] == val) { - right -= 1; - continue; - } - - nums[left] = nums[right]; - left += 1; - right -= 1; - } - - return left; - } -}; -``` - -## JavaScript - -```javascript -var removeElement = function (nums, val) { - let left = 0 - let right = nums.length - 1 - - while (left <= right) { - if (nums[left] != val) { - left += 1 - continue - } - - if (nums[right] == val) { - right -= 1 - continue - } - - nums[left] = nums[right] - left += 1 - right -= 1 - } - - return left -}; -``` - -## C# - -```csharp -public class Solution -{ - public int RemoveElement(int[] nums, int val) - { - int left = 0; - int right = nums.Length - 1; - - while (left <= right) - { - if (nums[left] != val) - { - left += 1; - continue; - } - - if (nums[right] == val) - { - right -= 1; - continue; - } - - nums[left] = nums[right]; - left += 1; - right -= 1; - } - - return left; - } -} -``` - -## Go - -```go -func removeElement(nums []int, val int) int { - left := 0 - right := len(nums) - 1 - - for left <= right { - if nums[left] != val { - left += 1 - continue - } - - if nums[right] == val { - right -= 1 - continue - } - - nums[left] = nums[right] - left++ - right-- - } - - return left -} -``` - -## Ruby - -```ruby -def remove_element(nums, val) - left = 0 - right = nums.size - 1 - - while left <= right - if nums[left] != val - left += 1 - next - end - - if (nums[right] == val) - right -= 1 - next - end - - nums[left] = nums[right] - left += 1 - right -= 1 - end - - left -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -- The `fast and slow pointer approach` means that both pointers initially point to the head of the array, and then one pointer moves faster. -- For this question, under what circumstances should the fast pointer move faster? When the value corresponding to the fast pointer is equal to *val*. The slow pointer must ensure that each value it passes through is not equal to *val*. -- The swap of values ​​occurs when the value pointed by the fast pointer is not equal to *val*, and the value pointed by the slow pointer is equal to *val*. -- This method is not easy to think of, but it is more concise than `two pointers of left and right`. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -class Solution { - public int removeElement(int[] nums, int val) { - var slowIndex = 0; - - for (var num : nums) { // This line is the most important. You'd better memorize it. - if (num != val) { - nums[slowIndex] = num; - slowIndex += 1; - } - } - - return slowIndex; - } -} -``` - -## Python - -```python -class Solution: - def removeElement(self, nums: List[int], val: int) -> int: - slow_index = 0 - - for num in nums: # This line is the most important. You'd better memorize it. - if num != val: - nums[slow_index] = num - slow_index += 1 - - return slow_index -``` - -## C++ - -```cpp -class Solution { -public: - int removeElement(vector& nums, int val) { - auto slow_index = 0; - - for (auto num : nums) { // This line is the most important. You'd better memorize it. - if (num != val) { - nums[slow_index] = num; - slow_index += 1; - } - } - - return slow_index; - } -}; -``` - -## JavaScript - -```javascript -var removeElement = function (nums, val) { - let slowIndex = 0 - - nums.forEach((num) => { // This line is the most important. You'd better memorize it. - if (num != val) { - nums[slowIndex] = num - slowIndex += 1 - } - }) - - return slowIndex -}; -``` - -## C# - -```csharp -public class Solution -{ - public int RemoveElement(int[] nums, int val) - { - int slowIndex = 0; - - foreach (int num in nums) // This line is the most important. You'd better memorize it. - { - if (num != val) - { - nums[slowIndex] = num; - slowIndex += 1; - } - } - - return slowIndex; - } -} -``` - -## Go - -```go -func removeElement(nums []int, val int) int { - slowIndex := 0 - - for _, num := range nums { // This line is the most important. You'd better memorize it. - if num != val { - nums[slowIndex] = num - slowIndex += 1 - } - } - - return slowIndex -} -``` - -## Ruby - -```ruby -def remove_element(nums, val) - slow_index = 0 - - nums.each do |num| # This line is the most important. You'd better memorize it. - if num != val - nums[slow_index] = num - slow_index += 1 - end - end - - slow_index -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [27. Remove Element - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/27-remove-element). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/279-perfect-squares.md b/en/1-1000/279-perfect-squares.md deleted file mode 100644 index d446efd..0000000 --- a/en/1-1000/279-perfect-squares.md +++ /dev/null @@ -1,178 +0,0 @@ -# 279. Perfect Squares -LeetCode link: [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/) - -## LeetCode problem description -> Given an integer `n`, return the **least** number of perfect square numbers that sum to `n`. - -A **perfect square** is an integer that is the square of an integer; in other words, it is the product of some integer with itself. For example, `1`, `4`, `9`, and 16 are perfect squares while `3` and `11` are not. -``` -------------------------------------------------------------- -[Example 1] - -Input: n = 12 -Output: 3 -Explanation: 12 = 4 + 4 + 4. -------------------------------------------------------------- -[Example 2] - -Input: n = 13 -Output: 2 -Explanation: 13 = 4 + 9. -------------------------------------------------------------- -[Constraints] - -1 <= n <= 10000 -------------------------------------------------------------- -``` - -## Thoughts -It is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * Sqrt(n))`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int NumSquares(int n) - { - int defaultValue = n + 2; // As long as the value is greater than 'n', it doesn't matter how much it is. - int[] dp = Enumerable.Repeat(defaultValue, n + 1).ToArray(); - dp[0] = 0; - - for (var i = 1; i < dp.Length; i++) - { - for (var j = 1; j * j <= i; j++) - { - dp[i] = Math.Min(dp[i], dp[i - j * j] + 1); - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def numSquares(self, n: int) -> int: - default_value = n + 2 # As long as the value is greater than 'n', it doesn't matter how much it is. - dp = [default_value] * (n + 1) - dp[0] = 0 - - for i in range(1, len(dp)): - j = 1 - while i >= j * j: - dp[i] = min(dp[i], dp[i - j * j] + 1) - j += 1 - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int numSquares(int n) { - auto default_value = n + 2; // As long as the value is greater than 'n', it doesn't matter how much it is. - auto dp = vector(n + 1, default_value); - dp[0] = 0; - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j * j <= i; j++) { - dp[i] = min(dp[i], dp[i - j * j] + 1); - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int numSquares(int n) { - var defaultValue = n + 2; // As long as the value is greater than 'n', it doesn't matter how much it is. - var dp = new int[n + 1]; - Arrays.fill(dp, defaultValue); - dp[0] = 0; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j * j <= i; j++) { - dp[i] = Math.min(dp[i], dp[i - j * j] + 1); - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -```javascript -var numSquares = function (n) { - const DEFAULT_VALUE = n + 2 // As long as the value is greater than 'n', it doesn't matter how much it is. - const dp = Array(n + 1).fill(DEFAULT_VALUE) - dp[0] = 0 - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j * j <= i; j++) { - dp[i] = Math.min(dp[i], dp[i - j * j] + 1) - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func numSquares(n int) int { - defaultValue := n + 2 // As long as the value is greater than 'n', it doesn't matter how much it is. - dp := slices.Repeat([]int{defaultValue}, n + 1) - dp[0] = 0 - - for i := 1; i < len(dp); i++ { - for j := 1; j * j <= i; j++ { - dp[i] = min(dp[i], dp[i - j * j] + 1) - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def num_squares(n) - default_value = n + 2 # As long as the value is greater than 'n', it doesn't matter how much it is. - dp = Array.new(n + 1, default_value) - dp[0] = 0 - - (1...dp.size).each do |i| - j = 1 - while i >= j * j - dp[i] = [ dp[i], dp[i - j * j] + 1 ].min - j += 1 - end - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md b/en/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md deleted file mode 100644 index daa9152..0000000 --- a/en/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md +++ /dev/null @@ -1,210 +0,0 @@ -# 28. Find the Index of the First Occurrence in a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [28. Find the Index of the First Occurrence in a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/28-find-the-index-of-the-first-occurrence-in-a-string) for a better experience! - -LeetCode link: [28. Find the Index of the First Occurrence in a String](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string), difficulty: **Easy**. - -## LeetCode description of "28. Find the Index of the First Occurrence in a String" - -Given two strings `needle` and `haystack`, return the **index** of the first occurrence of `needle` in `haystack`, or `-1` if `needle` is not part of `haystack`. - -### [Example 1] - -**Input**: `haystack = "sadbutsad", needle = "sad"` - -**Output**: `0` - -**Explanation**: - -

"sad" occurs at index 0 and 6.
-The first occurrence is at index 0, so we return 0.

- - -### [Example 2] - -**Input**: `haystack = "leetcode", needle = "leeto"` - -**Output**: `-1` - -**Explanation**: - -

"leeto" did not occur in "leetcode", so we return -1.

- - -### [Constraints] - -- `1 <= haystack.length, needle.length <= 10000` -- `haystack` and `needle` consist of only lowercase English characters. - -## Intuition - -- This kind of question can be solved with one line of code using the built-in `index()`. Obviously, the questioner wants to test our ability to control the loop. - -- For `heystack`, traverse each character in turn. There may be two situations: - 1. First, the character is not equal to the first letter of `needle`. Then process the next character. - 2. Second, if the character is equal to the first letter of `needle`, continue to compare the next character of `heystack` and `needle` in an internal loop until they are not equal or `needle` has completely matched. - -- This question is easier to understand by looking at the code directly. - -## Complexity - -- Time complexity: `O(N + M)`. -- Space complexity: `O(1)`. - -## Python - -```python -class Solution: - def strStr(self, haystack: str, needle: str) -> int: - for i in range(len(haystack)): - j = 0 - - while i + j < len(haystack) and haystack[i + j] == needle[j]: - j += 1 - - if j == len(needle): - return i - - return -1 -``` - -## JavaScript - -```javascript -var strStr = function (haystack, needle) { - for (let i = 0; i < haystack.length; i++) { - let j = 0 - - while (i + j < haystack.length && haystack[i + j] == needle[j]) { - j += 1 - - if (j == needle.length) { - return i - } - } - } - - return -1 -}; -``` - -## Ruby - -```ruby -# @param {String} haystack -# @param {String} needle -# @return {Integer} -def str_str(haystack, needle) - (0...haystack.length).each do |i| - j = 0 - - while i + j < haystack.length && haystack[i + j] == needle[j] - j += 1 - - return i if j == needle.length - end - end - - -1 -end -``` - -## C++ - -```cpp -class Solution { -public: - int strStr(string haystack, string needle) { - for (int i = 0; i < haystack.length(); i++) { - int j = 0; - - while (i + j < haystack.length() && haystack[i + j] == needle[j]) { - j++; - - if (j == needle.length()) { - return i; - } - } - } - - return -1; - } -}; -``` - -## Java - -```java -class Solution { - public int strStr(String haystack, String needle) { - for (int i = 0; i < haystack.length(); i++) { - int j = 0; - - while (i + j < haystack.length() && haystack.charAt(i + j) == needle.charAt(j)) { - j++; - - if (j == needle.length()) { - return i; - } - } - } - - return -1; - } -} -``` - -## Go - -```go -func strStr(haystack string, needle string) int { - for i := 0; i < len(haystack); i++ { - j := 0 - - for i+j < len(haystack) && haystack[i+j] == needle[j] { - j++ - - if j == len(needle) { - return i - } - } - } - - return -1 -} -``` - -## C# - -```csharp -public class Solution { - public int StrStr(string haystack, string needle) { - for (int i = 0; i < haystack.Length; i++) { - int j = 0; - - while (i + j < haystack.Length && haystack[i + j] == needle[j]) { - j++; - - if (j == needle.Length) { - return i; - } - } - } - - return -1; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [28. Find the Index of the First Occurrence in a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/28-find-the-index-of-the-first-occurrence-in-a-string). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/300-longest-increasing-subsequence.md b/en/1-1000/300-longest-increasing-subsequence.md deleted file mode 100644 index b5ca3bf..0000000 --- a/en/1-1000/300-longest-increasing-subsequence.md +++ /dev/null @@ -1,143 +0,0 @@ -# 300. Longest Increasing Subsequence -LeetCode link: [300. Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) - -## LeetCode problem description -Given an integer array `nums`, return the length of the **longest strictly increasing subsequence**. - -``` -------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [10,9,2,5,3,7,101,18] -Output: 4 - -Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. -------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [0,1,0,3,2,3] -Output: 4 -------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums = [7,7,7,7,7,7,7] -Output: 1 -------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 2500 --10000 <= nums[i] <= 10000 -------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 4 to 7 languages are given. - -### Complexity -* Time: `O(n * n)`. -* Space: `O(n)`. - -## C# -```c# -// 10, 9, 2, 5, 3, 7, 4, 3,101,18 # nums -// 1, 1, 1, 2, 2, 3, 3, 2, 4,4 # dp -public class Solution -{ - public int LengthOfLIS(int[] nums) - { - var dp = new int[nums.Length]; - Array.Fill(dp, 1); - - for (var i = 1; i < nums.Length; i++) - { - for (var j = i - 1; j >= 0; j--) - { - if (nums[i] > nums[j]) - { - dp[i] = Math.Max(dp[i], dp[j] + 1); - } - } - } - - return dp.Max(); - } -} -``` - -## Python -```python -class Solution: - def lengthOfLIS(self, nums: List[int]) -> int: - dp = [1] * len(nums) - - for i in range(1, len(dp)): - for j in range(i - 1, -1, -1): - if nums[i] > nums[j] and dp[j] + 1 > dp[i]: - dp[i] = dp[j] + 1 - - return max(dp) -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -class Solution { - public int lengthOfLIS(int[] nums) { - var dp = new int[nums.length]; - Arrays.fill(dp, 1); - - for (var i = 1; i < nums.length; i++) { - for (var j = i - 1; j >= 0; j--) { - if (nums[i] > nums[j]) { - dp[i] = Math.max(dp[i], dp[j] + 1); - } - } - } - - return IntStream.of(dp).max().getAsInt(); - } -} -``` - -## JavaScript -```javascript -var lengthOfLIS = function (nums) { - const dp = Array(nums.length).fill(1) - - nums.forEach((num, i) => { - for (let j = i - 1; j >= 0; j--) { - if (num > nums[j]) { - dp[i] = Math.max(dp[i], dp[j] + 1) - } - } - }) - - return Math.max(...dp) -}; -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/303-range-sum-query-immutable.md b/en/1-1000/303-range-sum-query-immutable.md deleted file mode 100644 index 592cab3..0000000 --- a/en/1-1000/303-range-sum-query-immutable.md +++ /dev/null @@ -1,240 +0,0 @@ -# 303. Range Sum Query - Immutable - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [303. Range Sum Query - Immutable - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/303-range-sum-query-immutable) for a better experience! - -LeetCode link: [303. Range Sum Query - Immutable](https://leetcode.com/problems/range-sum-query-immutable), difficulty: **Easy**. - -## LeetCode description of "303. Range Sum Query - Immutable" - -Given an integer array `nums`, handle multiple queries of the following type: - -1. Calculate the sum of the elements of `nums` between indices `left` and `right` inclusive where `left <= right`. - -Implement the `NumArray` class: - -- `NumArray(int[] nums)` Initializes the object with the integer array `nums`. -- `int sumRange(int left, int right)` Returns the **sum** of the elements of `nums` between indices `left` and `right` **inclusive** (i.e. `nums[left] + nums[left + 1] + ... + nums[right]`). - -### [Example 1] - -**Input**: `["NumArray", "sumRange", "sumRange", "sumRange"] [[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]` - -**Output**: `[null, 1, -1, -3]` - -**Explanation**: - -

NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
-numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
-numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
-numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3

- - -### [Constraints] - -- `1 <= nums.length <= 10^4` -- `-10^5 <= nums[i] <= 10^5` -- `0 <= left <= right < nums.length` -- At most `10^4` calls will be made to `sumRange`. - -## Intuition 1 - -- Use a new array `prefix_sums` to save the sum of the previous elements. -- The first element of `prefix_sums` is `0` because the prefix sum **does not include the current element**. -- To find the `sum` of the elements from index `left` to `right` (inclusive), just use `prefix_sums[right + 1] - prefix_sums[left]`. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class NumArray { - private int[] prefixSums; - - public NumArray(int[] nums) { - prefixSums = new int[nums.length + 1]; - var sum = 0; - - for (var i = 0; i < nums.length; i++) { - sum += nums[i]; - prefixSums[i + 1] = sum; - } - } - - public int sumRange(int left, int right) { - return prefixSums[right + 1] - prefixSums[left]; - } -} -``` - -## Python - -```python -class NumArray: - def __init__(self, nums: List[int]): - self.prefix_sums = [0] - sum_ = 0 - - for num in nums: - sum_ += num - self.prefix_sums.append(sum_) - - def sumRange(self, left: int, right: int) -> int: - return self.prefix_sums[right + 1] - self.prefix_sums[left] -``` - -## C++ - -```cpp -class NumArray { -private: - vector prefixSums; - -public: - NumArray(vector& nums) { - prefixSums.push_back(0); - auto sum = 0; - - for (auto num : nums) { - sum += num; - prefixSums.push_back(sum); - } - } - - int sumRange(int left, int right) { - return prefixSums[right + 1] - prefixSums[left]; - } -}; -``` - -## JavaScript - -```javascript -let prefixSums - -var NumArray = function (nums) { - prefixSums = [0] - let sum = 0 - - nums.forEach((num) => { - sum += num - prefixSums.push(sum) - }) -}; - -NumArray.prototype.sumRange = function (left, right) { - return prefixSums[right + 1] - prefixSums[left] -}; -``` - -## C# - -```csharp -public class NumArray -{ - int[] prefixSums; - - public NumArray(int[] nums) - { - prefixSums = new int[nums.Length + 1]; - int sum = 0; - - for (int i = 0; i < nums.Length; i++) - { - sum += nums[i]; - prefixSums[i + 1] = sum; - } - } - - public int SumRange(int left, int right) - { - return prefixSums[right + 1] - prefixSums[left]; - } -} -``` - -## Go - -```go -type NumArray struct { - prefixSums []int -} - -func Constructor(nums []int) NumArray { - prefixSums := make([]int, len(nums) + 1) - sum := 0 - - for i, num := range nums { - sum += num - prefixSums[i + 1] = sum - } - - return NumArray{prefixSums} -} - -func (this *NumArray) SumRange(left int, right int) int { - return this.prefixSums[right + 1] - this.prefixSums[left] -} -``` - -## Ruby - -```ruby -class NumArray - def initialize(nums) - @prefix_sums = [0] - sum = 0 - - nums.each do |num| - sum += num - @prefix_sums << sum - end - end - - def sum_range(left, right) - @prefix_sums[right + 1] - @prefix_sums[left] - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -Directly returning the sum of the values ​​in the array range can pass the test, but it will fail if the test case is stricter. -So we still need to learn a more efficient solution: `Prefix Sum` solution. - -## Complexity - -- Time complexity: `O(M * N)`. -- Space complexity: `O(M * N)`. - -## Python - -```python -class NumArray: - def __init__(self, nums: List[int]): - self.nums = nums - - def sumRange(self, left: int, right: int) -> int: - return sum(self.nums[left:right + 1]) -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [303. Range Sum Query - Immutable - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/303-range-sum-query-immutable). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md b/en/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md deleted file mode 100644 index 547f3da..0000000 --- a/en/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md +++ /dev/null @@ -1,140 +0,0 @@ -# 309. Best Time to Buy and Sell Stock with Cooldown -LeetCode link: [309. Best Time to Buy and Sell Stock with Cooldown](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -Find the **maximum profit** you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions: - -* After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day). - -**Note**: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). - -``` -------------------------------------------------------------------------- -[Example 1] - -Input: prices = [1,2,3,0,2] -Output: 3 - -Explanation: transactions = [buy, sell, cooldown, buy, sell] -------------------------------------------------------------------------- -[Example 2] - -Input: prices = [1] -Output: 0 -------------------------------------------------------------------------- -[Constraints] - -1 <= prices.length <= 5000 -0 <= prices[i] <= 1000 -------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - # 2 states: - # 0: hold stock - # 1) keep holding (last day is not a cooldown day) - # 2) today just bought (last day is a cooldown day) - # 1: no stock - # 1) keep no stock (today is not a cooldown day) - # 2) keep no stock (today is a cooldown day) - # 3) today just sold - # - # To make things clear, we have to go with 3 states. - # The process from 2 states to 3 states really makes things easier to understand! - # 3 states: - # 0: hold stock - # 1) keep holding (last day is not a cooldown day) - # 2) today just bought (last day is a cooldown day) - # 1: no stock (today is not a cooldown day) - # 1) keep no stock - # 2) today just sold - # 2: no stock (today is a cooldown day) - dp = [-prices[0], 0, 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], dc[2] - price) - dp[1] = max(dc[1], dc[0] + price) - dp[2] = dc[1] - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function(prices) { - const dp = [-prices[0], 0, 0] - - for (const price of prices.slice(1,)) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], dc[2] - price) - dp[1] = Math.max(dc[1], dc[0] + price) - dp[2] = dc[1] - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0, 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], dc[2] - prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i]) - dp[2] = dc[1] - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/322-coin-change.md b/en/1-1000/322-coin-change.md deleted file mode 100644 index fbca4eb..0000000 --- a/en/1-1000/322-coin-change.md +++ /dev/null @@ -1,214 +0,0 @@ -# 322. Coin Change -LeetCode link: [322. Coin Change](https://leetcode.com/problems/coin-change/) - -## LeetCode problem description -> You are given an integer array `coins` representing coins of different denominations and an integer `amount` representing a total amount of money. - -Return the **fewest number** of coins that you need to make up that `amount`. If that amount of money cannot be made up by any combination of the coins, return `-1`. - -You may assume that you have an **infinite** number of each kind of coin. - -``` -Example 1: - -Input: coins = [1,2,5], amount = 11 -Output: 3 - -Explanation: 11 = 5 + 5 + 1 ------------------------------------------------------------------------- - -Example 2: - -Input: coins = [2], amount = 3 -Output: -1 ------------------------------------------------------------------------- - -Constraints: - -1 <= coins.length <= 12 -1 <= coins[i] <= 2**31 - 1 -0 <= amount <= 10000 -``` - -## Thoughts -It is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int CoinChange(int[] coins, int amount) - { - int defaultValue = amount + 2; // As long as the value is greater than 'amount', it doesn't matter how much it is. - int[] dp = Enumerable.Repeat(defaultValue, amount + 1).ToArray(); - dp[0] = 0; - - for (var i = 1; i < dp.Length; i++) - { - foreach (int coin in coins) - { - if (i >= coin) - { - dp[i] = Math.Min(dp[i], dp[i - coin] + 1); - } - } - } - - if (dp.Last() == defaultValue) - return -1; - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def coinChange(self, coins: List[int], amount: int) -> int: - default_value = amount + 2 # As long as the value is greater than 'amount', it doesn't matter how much it is. - dp = [default_value] * (amount + 1) - dp[0] = 0 - - for i in range(1, len(dp)): - for coin in coins: - if i >= coin: - dp[i] = min(dp[i], dp[i - coin] + 1) - - if dp[-1] == default_value: - return -1 - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int coinChange(vector& coins, int amount) { - auto default_value = amount + 2; // As long as the value is greater than 'amount', it doesn't matter how much it is. - auto dp = vector(amount + 1, default_value); - dp[0] = 0; - - for (auto i = 1; i < dp.size(); i++) { - for (auto coin : coins) { - if (i >= coin) { - dp[i] = min(dp[i], dp[i - coin] + 1); - } - } - } - - if (dp.back() == default_value) { - return -1; - } - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int coinChange(int[] coins, int amount) { - var defaultValue = amount + 2; // As long as the value is greater than 'amount', it doesn't matter how much it is. - - var dp = new int[amount + 1]; - Arrays.fill(dp, defaultValue); - dp[0] = 0; - - for (var i = 1; i < dp.length; i++) { - for (var coin : coins) { - if (i >= coin) { - dp[i] = Math.min(dp[i], dp[i - coin] + 1); - } - } - } - - var result = dp[dp.length - 1]; - if (result == defaultValue) { - return -1; - } - return result; - } -} -``` - -## JavaScript -```javascript -var coinChange = function (coins, amount) { - const DEFAULT_VALUE = amount + 2 // As long as the value is greater than 'amount', it doesn't matter how much it is. - const dp = Array(amount + 1).fill(DEFAULT_VALUE) - dp[0] = 0 - - for (let i = 1; i < dp.length; i++) { - for (const coin of coins) { - if (i >= coin) { - dp[i] = Math.min(dp[i], dp[i - coin] + 1) - } - } - } - - if (dp.at(-1) == DEFAULT_VALUE) { - return -1 - } - return dp.at(-1) -}; -``` - -## Go -```go -func coinChange(coins []int, amount int) int { - defaultValue := amount + 2 // As long as the value is greater than 'amount', it doesn't matter how much it is. - dp := slices.Repeat([]int{defaultValue}, amount + 1) - dp[0] = 0 - - for i := 1; i < len(dp); i++ { - for _, coin := range coins { - if i >= coin { - dp[i] = min(dp[i], dp[i - coin] + 1) - } - } - } - - result := dp[len(dp) - 1] - if result == defaultValue { - return -1 - } - return result -} -``` - -## Ruby -```ruby -def coin_change(coins, amount) - default_value = amount + 2 # As long as the value is greater than 'amount', it doesn't matter how much it is. - dp = Array.new(amount + 1, default_value) - dp[0] = 0 - - (1...dp.size).each do |i| - coins.each do |coin| - dp[i] = [ dp[i], dp[i - coin] + 1 ].min if i >= coin - end - end - - return -1 if dp[-1] == default_value - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/337-house-robber-iii.md b/en/1-1000/337-house-robber-iii.md deleted file mode 100644 index c82a91e..0000000 --- a/en/1-1000/337-house-robber-iii.md +++ /dev/null @@ -1,244 +0,0 @@ -# 337. House Robber III -LeetCode link: [337. House Robber III](https://leetcode.com/problems/house-robber-iii/) - -## LeetCode problem description -The thief has found himself a new place for his thievery again. There is only one entrance to this area, called `root`. - -Besides the `root`, each house has one and only one parent house. After a tour, the smart thief realized that all houses in this place form a binary tree. **It will automatically contact the police if two directly-linked houses were broken into on the same night**. - -Given the `root` of the binary tree, return the **maximum amount of money** the thief can rob **without alerting the police**. -``` ------------------------------------------------------------------------- -[Example 1] - -Input: root = [3,2,3,null,3,null,1] -Output: 7 -Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7. ------------------------------------------------------------------------- -[Example 2] - -Input: root = [3,4,5,1,3,null,1] -Output: 9 -Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9. ------------------------------------------------------------------------- -[Constraints] - -The number of nodes in the tree is in the range [1, 10000]. -0 <= Node.val <= 10000 ------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3-7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Solution 1: Easier to understand -```python -class Solution: - def __init__(self): - self.node_to_money = defaultdict(int) - - # Uncomment the next line, you can solve it without using `self.node_to_money` dict. - # @cache - def rob(self, node: Optional[TreeNode]) -> int: - if node is None: - return 0 - - if node in self.node_to_money: - return self.node_to_money[node] - - money_exclude_node = self.rob(node.left) + self.rob(node.right) - - money_include_node = node.val - if node.left: - money_include_node += self.rob(node.left.left) + self.rob(node.left.right) - if node.right: - money_include_node += self.rob(node.right.left) + self.rob(node.right.right) - - self.node_to_money[node] = max(money_exclude_node, money_include_node) - - return self.node_to_money[node] -``` - -### Solution 2: Most concise -```python -class Solution: - def rob(self, root: Optional[TreeNode]) -> int: - return max(self.rob_tree(root)) - - def rob_tree(self, node): - if node is None: - return 0, 0 - - left_pair = self.rob_tree(node.left) - right_pair = self.rob_tree(node.right) - - return max(left_pair) + max(right_pair), node.val + left_pair[0] + right_pair[0] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -### Solution 1: Easier to understand -```javascript -const nodeToMoney = new Map() - -var rob = function (root) { - nodeToMoney.clear() - - return robTree(root) -}; - - -function robTree(node) { - if (node == null) { - return 0 - } - - if (nodeToMoney.has(node)) { - return nodeToMoney.get(node) - } - - const moneyExcludeNode = robTree(node.left) + robTree(node.right) - - let moneyIncludeNode = node.val - if (node.left) { - moneyIncludeNode += robTree(node.left.left) + robTree(node.left.right) - } - if (node.right) { - moneyIncludeNode += robTree(node.right.left) + robTree(node.right.right) - } - - nodeToMoney.set(node, Math.max(moneyExcludeNode, moneyIncludeNode)) - - return nodeToMoney.get(node) -} -``` - -### Solution 2: Most concise -```javascript -var rob = function (root) { - return Math.max(...robTree(root)) -}; - -function robTree(node) { - if (node == null) { - return [0, 0] - } - - const leftPair = robTree(node.left) - const rightPair = robTree(node.right) - - return [ - Math.max(...leftPair) + Math.max(...rightPair), - node.val + leftPair[0] + rightPair[0] - ] -} -``` - -## Go -### Solution 1: Easier to understand -```go -/** - * Definition for a binary tree node. - * type TreeNode struct { - * Val int - * Left *TreeNode - * Right *TreeNode - * } - */ -func rob(root *TreeNode) int { - nodeToMoney := map[*TreeNode]int{} - - var robTree func (*TreeNode) int - - robTree = func (node *TreeNode) int { - if node == nil { - return 0 - } - - if money, ok := nodeToMoney[node]; ok { - return money - } - - moneyExcludeNode := robTree(node.Left) + robTree(node.Right) - - moneyIncludeNode := node.Val - if node.Left != nil { - moneyIncludeNode += robTree(node.Left.Left) + robTree(node.Left.Right) - } - if node.Right != nil { - moneyIncludeNode += robTree(node.Right.Left) + robTree(node.Right.Right) - } - - nodeToMoney[node] = max(moneyExcludeNode, moneyIncludeNode) - - return nodeToMoney[node] - } - - return robTree(root) -} -``` - -### Solution 2: Most concise -```go -/** - * Definition for a binary tree node. - * type TreeNode struct { - * Val int - * Left *TreeNode - * Right *TreeNode - * } - */ -func rob(root *TreeNode) int { - return slices.Max(robTree(root)) -} - -func robTree(node *TreeNode) []int { - if node == nil { - return []int{0, 0} - } - - leftPair := robTree(node.Left) - rightPair := robTree(node.Right) - - return []int{ - slices.Max(leftPair) + slices.Max(rightPair), - node.Val + leftPair[0] + rightPair[0], - } -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/344-reverse-string.md b/en/1-1000/344-reverse-string.md deleted file mode 100644 index 98ff280..0000000 --- a/en/1-1000/344-reverse-string.md +++ /dev/null @@ -1,220 +0,0 @@ -# 344. Reverse String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [344. Reverse String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/344-reverse-string) for a better experience! - -LeetCode link: [344. Reverse String](https://leetcode.com/problems/reverse-string), difficulty: **Easy**. - -## LeetCode description of "344. Reverse String" - -Write a function that reverses a string. The input string is given as an array of characters `s`. - -You must do this by modifying the input array [in-place](https://en.wikipedia.org/wiki/In-place_algorithm) with `O(1)` extra memory. - -### [Example 1] - -**Input**: `s = ["h","e","l","l","o"]` - -**Output**: `["o","l","l","e","h"]` - -### [Example 2] - -**Input**: `s = ["H","a","n","n","a","h"]` - -**Output**: `["h","a","n","n","a","H"]` - -### [Constraints] - -- `1 <= s.length <= 10^5` -- `s[i]` is a [printable ascii character](https://en.wikipedia.org/wiki/ASCII#Printable_characters). - -### [Hints] - -
- Hint 1 - The entire logic for reversing a string is based on using the opposite directional two-pointer approach! - - -
- -## Intuition - -1. This problem can be solved in one line of code using the built-in `sort()` method of the programming language. If this question is asked in an interview, the questioner should be testing how to do it without the built-in method. -2. Use **two pointers** with **opposite directions**, initially one pointer points to the index `0` and the other pointer points to the index `s.length - 1`. -3. Traverse the elements of the array, and the loop condition is `while (left < right)`. In the loop body, `left += 1`, `right -= 1`. -4. In the loop body, swap the two values. -5. The above is the template for `two pointers` in `opposite directions`. - -## Step by Step Solutions - -1. Use two pointers with **opposite directions**, initially one pointer points to the index `0` and the other pointer points to the index `s.length - 1`. - - ```ruby - left = 0 - right = s.length - 1 - ``` - -2. Traverse the elements of the array, and the loop condition is `while (left < right)`. In the loop body, `left += 1`, `right -= 1`. - - ```ruby - left = 0 - right = s.length - 1 - - while left < right # 1 - left += 1 # 2 - right -= 1 # 3 - end - ``` - -3. In the loop body, swap the two values. - - ```ruby - left = 0 - right = s.length - 1 - - while left < right - s[left], s[right] = s[right], s[left] # 1 - - left += 1 - right -= 1 - end - ``` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Java - -```java -class Solution { - public void reverseString(char[] s) { - var left = 0; - var right = s.length - 1; - - while (left < right) { - var leftValue = s[left]; - s[left] = s[right]; - s[right] = leftValue; - - left++; - right--; - } - } -} -``` - -## Python - -```python -class Solution: - def reverseString(self, s: List[str]) -> None: - left = 0 - right = len(s) - 1 - - while left < right: - s[left], s[right] = s[right], s[left] - left += 1 - right -= 1 -``` - -## C++ - -```cpp -class Solution { -public: - void reverseString(vector& s) { - auto left = 0; - auto right = s.size() - 1; - - while (left < right) { - swap(s[left], s[right]); - - left++; - right--; - } - } -}; -``` - -## JavaScript - -```javascript -var reverseString = function (s) { - let left = 0 - let right = s.length - 1 - - while (left < right) { - [s[left], s[right]] = [s[right], s[left]] - - left++ - right-- - } -}; -``` - -## C# - -```csharp -public class Solution -{ - public void ReverseString(char[] s) - { - int left = 0; - int right = s.Length - 1; - - while (left < right) - { - (s[left], s[right]) = (s[right], s[left]); - - left++; - right--; - } - } -} -``` - -## Go - -```go -func reverseString(s []byte) { - left := 0 - right := len(s) - 1 - - for left < right { - s[left], s[right] = s[right], s[left] - - left++ - right-- - } -} -``` - -## Ruby - -```ruby -def reverse_string(s) - left = 0 - right = s.size - 1 - - while left < right - s[left], s[right] = s[right], s[left] - - left += 1 - right -= 1 - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [344. Reverse String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/344-reverse-string). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/345-reverse-vowels-of-a-string.md b/en/1-1000/345-reverse-vowels-of-a-string.md deleted file mode 100644 index f26e390..0000000 --- a/en/1-1000/345-reverse-vowels-of-a-string.md +++ /dev/null @@ -1,302 +0,0 @@ -# 345. Reverse Vowels of a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [345. Reverse Vowels of a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/345-reverse-vowels-of-a-string) for a better experience! - -LeetCode link: [345. Reverse Vowels of a String](https://leetcode.com/problems/reverse-vowels-of-a-string), difficulty: **Easy**. - -## LeetCode description of "345. Reverse Vowels of a String" - -Given a string `s`, reverse only all the vowels in the string and return it. - -The vowels are `'a'`, `'e'`, `'i'`, `'o'`, and `'u'`, and they can appear in both lower and upper cases, more than once. - -### [Example 1] - -**Input**: `s = "IceCreAm"` - -**Output**: `"AceCreIm"` - -**Explanation**: - -

The vowels in s are ['I', 'e', 'e', 'A']. On reversing the vowels, s becomes "AceCreIm".

- - -### [Example 2] - -**Input**: `"leetcode"` - -**Output**: `"leotcede"` - -### [Constraints] - -- `1 <= s.length <= 3 * 10^5` -- `s` consist of **printable ASCII** characters. - -## Intuition - -Use two pointers to swap vowels in the string. The left pointer finds vowels from the start, the right pointer finds vowels from the end, and they swap until the pointers meet. - -## Pattern of "left & right pointers" - -The code framework is as follows: - -```java -int r = target.length() - 1; - -for (int l = 0; l < target.length(); l++) { // Important - // ... - if (l >= r) { - break; - } - - // ... - r--; -} -``` - -## Step by Step Solutions - -1. Initialize a set of vowels -2. For some languages, convert the string to a character array (since strings are immutable) -3. Left pointer `l` starts at `0`, right pointer `r` starts at the end -4. Loop processing: - - Move `l` right until a vowel is found - - Move `r` left until a vowel is found - - Swap the two vowels when `l < r` -5. Return the processed string - -## Complexity - -> Space complexity is O(N) if converting to a character array - -- Time complexity: `O(N)`. -- Space complexity: `O(1) or O(N)`. - -## Python - -```python -class Solution: - def reverseVowels(self, s: str) -> str: - vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'] - s = list(s) - r = len(s) - 1 - - for l in range(len(s)): # Important - if s[l] not in vowels: - continue - - while r > 0 and s[r] not in vowels: - r -= 1 - - if l >= r: - break - - s[l], s[r] = s[r], s[l] - r -= 1 - - return ''.join(s) -``` - -## Java - -```java -class Solution { - public String reverseVowels(String s) { - var vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); - var chars = s.toCharArray(); - int r = chars.length - 1; - - for (int l = 0; l < chars.length; l++) { // important - if (!vowels.contains(chars[l])) { - continue; - } - - while (r > 0 && !vowels.contains(chars[r])) { - r--; - } - - if (l >= r) { - break; - } - - // Swap the vowels - char temp = chars[l]; - chars[l] = chars[r]; - chars[r] = temp; - r--; - } - - return new String(chars); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string reverseVowels(string s) { - unordered_set vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'}; - int r = s.size() - 1; - - for (int l = 0; l < s.size(); l++) { // important - if (!vowels.contains(s[l])) { - continue; - } - - while (r > 0 && !vowels.contains(s[r])) { - r--; - } - - if (l >= r) { - break; - } - - swap(s[l], s[r]); - r--; - } - - return s; - } -}; -``` - -## JavaScript - -```javascript -var reverseVowels = function (s) { - const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) - const chars = s.split('') - let r = chars.length - 1 - - for (let l = 0; l < chars.length; l++) { // important - if (!vowels.has(chars[l])) { - continue - } - - while (r > 0 && !vowels.has(chars[r])) { - r-- - } - - if (l >= r) { - break - } - - [chars[l], chars[r]] = [chars[r], chars[l]] - r-- - } - - return chars.join('') -}; -``` - -## Ruby - -```ruby -def reverse_vowels(s) - vowels = Set.new(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) - r = s.size - 1 - - (0...s.size).each do |l| - unless vowels.include?(s[l]) - next - end - - while r > 0 && !vowels.include?(s[r]) - r -= 1 - end - - if l >= r - break - end - - s[l], s[r] = s[r], s[l] - r -= 1 - end - - s -end -``` - -## C# - -```csharp -public class Solution -{ - public string ReverseVowels(string s) - { - var vowels = new HashSet {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'}; - var chars = s.ToCharArray(); - int r = chars.Length - 1; - // important - for (int l = 0; l < chars.Length; l++) - { - if (!vowels.Contains(chars[l])) - { - continue; - } - - while (r > 0 && !vowels.Contains(chars[r])) - { - r--; - } - - if (l >= r) - { - break; - } - - (chars[l], chars[r]) = (chars[r], chars[l]); - r--; - } - - return new string(chars); - } -} -``` - -## Go - -```go -func reverseVowels(s string) string { - vowels := map[byte]bool{ - 'a': true, 'e': true, 'i': true, 'o': true, 'u': true, - 'A': true, 'E': true, 'I': true, 'O': true, 'U': true, - } - chars := []byte(s) - r := len(chars) - 1 - - for l := 0; l < len(chars); l++ { // important - if !vowels[chars[l]] { - continue - } - - for r > 0 && !vowels[chars[r]] { - r-- - } - - if l >= r { - break - } - - chars[l], chars[r] = chars[r], chars[l] - r-- - } - - return string(chars) -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [345. Reverse Vowels of a String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/345-reverse-vowels-of-a-string). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/349-intersection-of-two-arrays.md b/en/1-1000/349-intersection-of-two-arrays.md deleted file mode 100644 index 6e7d927..0000000 --- a/en/1-1000/349-intersection-of-two-arrays.md +++ /dev/null @@ -1,195 +0,0 @@ -# 349. Intersection of Two Arrays - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [349. Intersection of Two Arrays - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/349-intersection-of-two-arrays) for a better experience! - -LeetCode link: [349. Intersection of Two Arrays](https://leetcode.com/problems/intersection-of-two-arrays), difficulty: **Easy**. - -## LeetCode description of "349. Intersection of Two Arrays" - -Given two integer arrays `nums1` and `nums2`, return _an array of their **intersection**_. -Each element in the result must be **unique** and you may return the result in **any order**. - -> Array Intersection: The intersection of two arrays is defined as the set of elements that are present in both arrays. - - -### [Example 1] - -**Input**: `nums1 = [1,2,2,1], nums2 = [2,2]` - -**Output**: `[2]` - -### [Example 2] - -**Input**: `nums1 = [4,9,5], nums2 = [9,4,9,8,4]` - -**Output**: `[9,4]` - -**Explanation**: `[4,9] is also accepted.` - -### [Constraints] - -- `1 <= nums1.length, nums2.length <= 1000` -- `0 <= nums1[i], nums2[i] <= 1000` - -## Intuition - -1. Convert one of the arrays to a `set`. The elements are unique in a `set`. -2. When traversing the other array, if an element is found to already exist in the `set`, it means that the element belongs to the intersection, and the element should be added to the `results`. -3. The `results` is also of `set` type because duplicate removal is required. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public int[] intersection(int[] nums1, int[] nums2) { - var results = new HashSet(); - var num1Set = new HashSet(); - - for (var num : nums1) { - num1Set.add(num); - } - - for (var num : nums2) { - if (num1Set.contains(num)) { - results.add(num); - } - } - - return results.stream().mapToInt(num -> num).toArray(); - } -} -``` - -## Python - -```python -class Solution: - def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: - set_of_nums1 = set(nums1) - results = set() - - for num in nums2: - if num in set_of_nums1: - results.add(num) - - return list(results) -``` - -## C++ - -```cpp -class Solution { -public: - vector intersection(vector& nums1, vector& nums2) { - unordered_set results; - unordered_set set_of_nums1(nums1.begin(), nums1.end()); - - for (auto num : nums2) { - if (set_of_nums1.contains(num)) { - results.insert(num); - } - } - - return vector(results.begin(), results.end()); - } -}; -``` - -## JavaScript - -```javascript -var intersection = function (nums1, nums2) { - let results = new Set() - let num1Set = new Set(nums1) - - for (const num of nums2) { - if (num1Set.has(num)) { - results.add(num) - } - } - - return Array.from(results) -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] Intersection(int[] nums1, int[] nums2) - { - var results = new HashSet(); - var num1Set = new HashSet(); - - foreach (int num in nums1) - num1Set.Add(num); - - foreach (int num in nums2) - { - if (num1Set.Contains(num)) - { - results.Add(num); - } - } - - return results.ToArray(); - } -} -``` - -## Go - -```go -func intersection(nums1 []int, nums2 []int) []int { - results := map[int]bool{} - num1Set := map[int]bool{} - - for _, num := range nums1 { - num1Set[num] = true - } - - for _, num := range nums2 { - if _, ok := num1Set[num]; ok { - results[num] = true - } - } - - return slices.Collect(maps.Keys(results)) -} -``` - -## Ruby - -```ruby -def intersection(nums1, nums2) - nums1_set = Set.new(nums1) - results = Set.new - - nums2.each do |num| - if nums1_set.include?(num) - results << num - end - end - - results.to_a -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [349. Intersection of Two Arrays - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/349-intersection-of-two-arrays). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/377-combination-sum-iv.md b/en/1-1000/377-combination-sum-iv.md deleted file mode 100644 index 9bd1a16..0000000 --- a/en/1-1000/377-combination-sum-iv.md +++ /dev/null @@ -1,192 +0,0 @@ -# 377. Combination Sum IV -LeetCode link: [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) - -## LeetCode problem description -> Given an array of **distinct** integers `nums` and a target integer `target`, return the number of possible combinations that add up to `target`. - -The test cases are generated so that the answer can fit in a 32-bit integer. - -``` -Example 1: - -Input: nums = [1,2,3], target = 4 -Output: 7 - -Explanation: -The possible combination ways are: -(1, 1, 1, 1) -(1, 1, 2) -(1, 2, 1) -(1, 3) -(2, 1, 1) -(2, 2) -(3, 1) -Note that different sequences are counted as different combinations. ------------------------------------------------------------------------- - -Example 2: - -Input: nums = [9], target = 3 -Output: 0 - ------------------------------------------------------------------------- - -Constraints: - -1 <= nums.length <= 200 -1 <= nums[i] <= 1000 -All the elements of 'nums' are 'unique'. -1 <= target <= 1000 -``` - -## Thoughts -This is `Unbounded Knapsack Problem` A, and it also requires us to consider the sequences. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int CombinationSum4(int[] nums, int target) - { - var dp = new int[target + 1]; - dp[0] = 1; - - for (var i = 1; i < dp.Length; i++) - { - foreach (var num in nums) - { - if (i >= num) - { - dp[i] += dp[i - num]; - } - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def combinationSum4(self, nums: List[int], target: int) -> int: - dp = [0] * (target + 1) - dp[0] = 1 - - for i in range(1, len(dp)): - for num in nums: - if i >= num: - dp[i] += dp[i - num] - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int combinationSum4(vector& nums, int target) { - vector dp(target + 1, 0); - dp[0] = 1; - - for (auto i = 1; i < dp.size(); i++) { - for (auto num : nums) { - if (i >= num) { - dp[i] += dp[i - num]; - } - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int combinationSum4(int[] nums, int target) { - var dp = new int[target + 1]; - dp[0] = 1; - - for (var i = 1; i < dp.length; i++) { - for (var num : nums) { - if (i >= num) { - dp[i] += dp[i - num]; - } - } - } - - return dp[target]; - } -} -``` - -## JavaScript -```javascript -var combinationSum4 = function (nums, target) { - const dp = Array(target + 1).fill(0) - dp[0] = 1 - - for (let i = 1; i < dp.length; i++) { - for (const num of nums) { - if (i >= num) { - dp[i] += dp[i - num] - } - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func combinationSum4(nums []int, target int) int { - dp := make([]int, target + 1) - dp[0] = 1 - - for i := 1; i < len(dp); i++ { - for _, num := range nums { - if i >= num { - dp[i] += dp[i - num] - } - } - } - - return dp[target] -} -``` - -## Ruby -```ruby -def combination_sum4(nums, target) - dp = Array.new(target + 1, 0) - dp[0] = 1 - - (1...dp.size).each do |i| - nums.each do |num| - dp[i] += dp[i - num] if i >= num - end - end - - return dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/383-ransom-note.md b/en/1-1000/383-ransom-note.md deleted file mode 100644 index 81d2441..0000000 --- a/en/1-1000/383-ransom-note.md +++ /dev/null @@ -1,252 +0,0 @@ -# 383. Ransom Note - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [383. Ransom Note - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/383-ransom-note) for a better experience! - -LeetCode link: [383. Ransom Note](https://leetcode.com/problems/ransom-note), difficulty: **Easy**. - -## LeetCode description of "383. Ransom Note" - -Given two strings `ransomNote` and `magazine`, return `true` if `ransomNote` can be constructed by using the letters from `magazine` and `false` otherwise. - -Each letter in `magazine` can only be used once in `ransomNote`. - -### [Example 1] - -**Input**: `ransomNote = "a", magazine = "b"` - -**Output**: `false` - -### [Example 2] - -**Input**: `ransomNote = "aa", magazine = "ab"` - -**Output**: `false` - -### [Example 3] - -**Input**: `ransomNote = "aa", magazine = "aab"` - -**Output**: `true` - -### [Constraints] - -- `1 <= ransomNote.length, magazine.length <= 10^5` -- `ransomNote` and `magazine` consist of lowercase English letters. - -## Intuition - -1. This question is equivalent to asking whether `magazine` can contain all the characters in `ransomNote`. - -2. First count `magazine` to get the number of words corresponding to each character, and store the result in `Map`. Each time is an addition one operation. - -3. What to do next? - -
Click to view the answer

Traverses `ransomNote` and subtracts one from the number corresponding to the current character (reverse operation). If the number of a character is less than 0, return `false`.

- -## Step by Step Solutions - -1. First count the characters in `magazine`, and store the results in `Map`. - - ```javascript - charToCount = new Map() - - for (character in magazine) { - charToCount[character] += 1 - } - ``` - -2. Then, traverse `ransomNote` and perform reverse operations on the data in `Map`. If the count of a character is less than 0, return `false`. - - ```javascript - charToCount = new Map() - - for (character in magazine) { - charToCount[character] += 1 - } - - for (character in ransomNote) { - charToCount[character] -= 1 - - if (charToCount[character] < 0) { - return false - } - } - - return true - ``` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public boolean canConstruct(String ransomNote, String magazine) { - var charToCount = new HashMap(); - - for (var character : magazine.toCharArray()) { - charToCount.put(character, charToCount.getOrDefault(character, 0) + 1); - } - - for (var character : ransomNote.toCharArray()) { - charToCount.put(character, charToCount.getOrDefault(character, 0) - 1); - - if (charToCount.get(character) < 0) { - return false; - } - } - - return true; - } -} -``` - -## Python - -```python -# from collections import defaultdict - -class Solution: - def canConstruct(self, ransomNote: str, magazine: str) -> bool: - char_to_count = defaultdict(int) - - for char in magazine: - char_to_count[char] += 1 - - for char in ransomNote: - char_to_count[char] -= 1 - - if char_to_count[char] < 0: - return False - - return True -``` - -## JavaScript - -```javascript -var canConstruct = function (ransomNote, magazine) { - const charToCount = new Map() - - for (const character of magazine) { - charToCount.set(character, (charToCount.get(character) || 0) + 1) - } - - for (const character of ransomNote) { - charToCount.set(character, (charToCount.get(character) || 0) - 1) - - if (charToCount.get(character) < 0) { - return false - } - } - - return true -}; -``` - -## C# - -```csharp -public class Solution -{ - public bool CanConstruct(string ransomNote, string magazine) - { - var charToCount = new Dictionary(); - - foreach (char character in magazine) - charToCount[character] = charToCount.GetValueOrDefault(character, 0) + 1; - - foreach (char character in ransomNote) - { - charToCount[character] = charToCount.GetValueOrDefault(character, 0) - 1; - - if (charToCount[character] < 0) - { - return false; - } - } - - return true; - } -} -``` - -## Ruby - -```ruby -def can_construct(ransom_note, magazine) - char_to_count = Hash.new(0) - - magazine.each_char { |c| char_to_count[c] += 1 } - - ransom_note.each_char do |c| - char_to_count[c] -= 1 - return false if char_to_count[c] < 0 - end - - true -end -``` - -## Go - -```go -func canConstruct(ransomNote string, magazine string) bool { - charToCount := make(map[rune]int) - - for _, char := range magazine { - charToCount[char]++ - } - - for _, char := range ransomNote { - charToCount[char]-- - - if charToCount[char] < 0 { - return false - } - } - - return true -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canConstruct(string ransomNote, string magazine) { - unordered_map char_to_count; - - for (char character : magazine) { - char_to_count[character]++; - } - - for (char character : ransomNote) { - char_to_count[character]--; - - if (char_to_count[character] < 0) { - return false; - } - } - - return true; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [383. Ransom Note - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/383-ransom-note). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/392-is-subsequence.md b/en/1-1000/392-is-subsequence.md deleted file mode 100644 index 3ab6d7f..0000000 --- a/en/1-1000/392-is-subsequence.md +++ /dev/null @@ -1,515 +0,0 @@ -# 392. Is Subsequence - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [392. Is Subsequence - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/392-is-subsequence) for a better experience! - -LeetCode link: [392. Is Subsequence](https://leetcode.com/problems/is-subsequence), difficulty: **Medium**. - -## LeetCode description of "392. Is Subsequence" - -Given two strings `s` and `t`, return `true` if `s` is a **subsequence** of `t`, or `false` otherwise. - -A **subsequence** of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., `"ace"` is a subsequence of `"abcde"` while `"aec"` is not). - - -**Follow up**: Suppose there are lots of incoming `s`, say `s1, s2, ..., sk` where `k >= 10^9`, and you want to check one by one to see if `t` has its subsequence. In this scenario, how would you change your code? - -### [Example 1] - -**Input**: `s = "abc", t = "ahbgdc"` - -**Output**: `true` - -### [Example 2] - -**Input**: `s = "axc", t = "ahbgdc"` - -**Output**: `false` - -### [Constraints] - -- `0 <= s.length <= 100` -- `0 <= t.length <= 10^4` -- `s` and `t` consist only of lowercase English letters. - -## Intuition 1 - -- Define two pointers, initially pointing to the heads of two strings respectively, and reference characters with `t[i]` and `s[j]`. -- During the traversal of `t`, `i` is automatically incremented by 1, and if `t[i] == s[j]`, then `j += 1`. -- If `j >= s.length`, return `true`. If `t` is traversed and still not returned in advance, return `false`. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Python - -```python -class Solution: - def isSubsequence(self, s: str, t: str) -> bool: - if s == "": - return True - - s_index = 0 - - for i in range(len(t)): - if t[i] == s[s_index]: - s_index += 1 - - if s_index >= len(s): - return True - - return False -``` - -## C++ - -```cpp -class Solution { -public: - bool isSubsequence(string s, string t) { - if (s.empty()) { - return true; - } - - int s_index = 0; - - for (int i = 0; i < t.length(); i++) { - if (t[i] == s[s_index]) { - s_index++; - - if (s_index >= s.length()) { - return true; - } - } - } - - return false; - } -}; -``` - -## Java - -```java -class Solution { - public boolean isSubsequence(String s, String t) { - if (s.isEmpty()) { - return true; - } - - int sIndex = 0; - - for (int i = 0; i < t.length(); i++) { - if (t.charAt(i) == s.charAt(sIndex)) { - sIndex++; - - if (sIndex >= s.length()) { - return true; - } - } - } - - return false; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public bool IsSubsequence(string s, string t) - { - if (string.IsNullOrEmpty(s)) - { - return true; - } - - int sIndex = 0; - - for (int i = 0; i < t.Length; i++) - { - if (t[i] == s[sIndex]) - { - sIndex++; - - if (sIndex >= s.Length) - { - return true; - } - } - } - - return false; - } -} -``` - -## Go - -```go -func isSubsequence(s string, t string) bool { - if len(s) == 0 { - return true - } - - sIndex := 0 - - for i := 0; i < len(t); i++ { - if t[i] == s[sIndex] { - sIndex++ - - if sIndex >= len(s) { - return true - } - } - } - - return false -} -``` - -## JavaScript - -```javascript -/** - * @param {string} s - * @param {string} t - * @return {boolean} - */ -var isSubsequence = function(s, t) { - if (s.length === 0) { - return true; - } - - let sIndex = 0; - - for (let i = 0; i < t.length; i++) { - if (t[i] === s[sIndex]) { - sIndex++; - - if (sIndex >= s.length) { - return true; - } - } - } - - return false; -}; -``` - -## Ruby - -```ruby -# @param {String} s -# @param {String} t -# @return {Boolean} -def is_subsequence(s, t) - return true if s.empty? - - s_index = 0 - - t.each_char.with_index do |char, i| - if char == s[s_index] - s_index += 1 - return true if s_index >= s.length - end - end - - false -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -- `Solution 1` is essentially a "dynamic programming" algorithm implemented with `rolling variables`. It is easy to understand, and the space complexity is reduced to `O(1)`. -- But now, not only do we not reduce the dimension, but we also increase the dimension. It will be more difficult to understand and implement. So why do this thankless task? -
Click to view the answer

Because it can handle a more complex scenario (e.g. [583. Delete Operation for Two Strings](583-delete-operation-for-two-strings.md)) that is common in dynamic programming.

-- In this question, can we use a `one-dimensional rolling array` to implement the "dynamic programming" algorithm? -
Click to view the answer

Of course, but considering that for this problem a `one-dimensional rolling array` is not as easy to understand as a `two-dimensional array`, and the implementation process is also prone to errors, so here I didn't give the relevant code implementation. If you are interested, you can try it.

-- The **compare two strings** question is about dealing with "two swappable arrays". After doing similar questions many times, we will form the intuition of using `two-dimensional arrays` for dynamic programming. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[i][j]`. - - `dp[i][j]` represents whether the first `i` letters of `s` are a subsequence of `t`'s first `j` letters. - - `dp[i][j]` is `true` or `false`. -2. Determine the `dp` array's initial value. - - Use an example: - - ``` - After initialization, the 'dp' array would be: - s = "abc", t = "ahbgdc" - # a h b g d c - # T T T T T T T # dp[0] - # a F F F F F F F - # b F F F F F F F - # c F F F F F F F - ``` - - `dp[0][j] = true` because `dp[0]` represents the empty string, and empty string is a subsequence of any string. - - `dp[i][j] = false (i != 0)`. -3. Fill in the `dp` grid data "in order" according to an example. - - ``` - 1. s = "a", t = "ahbgdc" - # a h b g d c - # T T T T T T T - # a F T T T T T T # dp[1] - ``` - ``` - 2. s = "ab", t = "ahbgdc" - # a h b g d c - # T T T T T T T - # a F T T T T T T - # b F F F T T T T - ``` - ``` - 3. s = "abc", t = "ahbgdc" - # a h b g d c - # T T T T T T T - # a F T T T T T T - # b F F F T T T T - # c F F F F F F T # dp[3] - ``` -4. Based on the `dp` grid data, derive the "recursive formula". - - ```ruby - if s[i - 1] == t[j - 1] - dp[i][j] = dp[i - 1][j - 1] - else - dp[i][j] = dp[i][j - 1] - end - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(N * M)`. -- Space complexity: `O(N * M)`. - -## Python - -```python -class Solution: - def isSubsequence(self, s: str, t: str) -> bool: - column_count = len(t) + 1 - dp = [[True] * column_count] - for _ in s: - dp.append([False] * column_count) - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if s[i - 1] == t[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = dp[i][j - 1] - - return dp[-1][-1] -``` - -## C++ - -```cpp -class Solution { -public: - bool isSubsequence(string s, string t) { - vector> dp(s.size() + 1, vector(t.size() + 1)); - fill(dp[0].begin(), dp[0].end(), true); - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (s[i - 1] == t[j - 1]) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = dp[i][j - 1]; - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript - -```javascript -var isSubsequence = function (s, t) { - const dp = Array(s.length + 1).fill().map( - () => Array(t.length + 1).fill(false) - ) - dp[0].fill(true) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (s[i - 1] == t[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = dp[i][j - 1] - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go - -```go -func isSubsequence(s string, t string) bool { - dp := make([][]bool, len(s) + 1) - columnSize := len(t) + 1 - dp[0] = slices.Repeat([]bool{true}, columnSize) - for i := 1; i < len(dp); i++ { - dp[i] = make([]bool, columnSize) - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if s[i - 1] == t[j - 1] { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = dp[i][j - 1] - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Java - -```java -class Solution { - public boolean isSubsequence(String s, String t) { - var dp = new boolean[s.length() + 1][t.length() + 1]; - Arrays.fill(dp[0], true); - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (s.charAt(i - 1) == t.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = dp[i][j - 1]; - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public bool IsSubsequence(string s, string t) - { - var dp = new bool[s.Length + 1, t.Length + 1]; - for (var j = 0; j < dp.GetLength(1); j++) - dp[0, j] = true; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (s[i - 1] == t[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1]; - } - else - { - dp[i, j] = dp[i, j - 1]; - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Ruby - -```ruby -def is_subsequence(s, t) - dp = Array.new(s.size + 1) do |i| - Array.new(t.size + 1, i == 0 ? true : false) - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if s[i - 1] == t[j - 1] - dp[i - 1][j - 1] - else - dp[i][j - 1] - end - end - end - - dp[-1][-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [392. Is Subsequence - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/392-is-subsequence). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/416-partition-equal-subset-sum.md b/en/1-1000/416-partition-equal-subset-sum.md deleted file mode 100644 index 857030a..0000000 --- a/en/1-1000/416-partition-equal-subset-sum.md +++ /dev/null @@ -1,609 +0,0 @@ -# 416. Partition Equal Subset Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [416. Partition Equal Subset Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/416-partition-equal-subset-sum) for a better experience! - -LeetCode link: [416. Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum), difficulty: **Medium**. - -## LeetCode description of "416. Partition Equal Subset Sum" - -Given an integer array `nums`, return `true` if you can partition the array into two subsets such that the sum of the elements in both subsets is equal or `false` otherwise. - -### [Example 1] - -**Input**: `nums = [1,5,11,5]` - -**Output**: `true` - -**Explanation**: - -

The array can be partitioned as [1, 5, 5] and [11].

- - -### [Example 2] - -**Input**: `nums = [1,2,3,5]` - -**Output**: `false` - -**Explanation**: - -

The array cannot be partitioned into equal sum subsets.

- - -### [Constraints] - -- `1 <= nums.length <= 200` -- `1 <= nums[i] <= 100` - -## Intuition 1 - -- When we first see this problem, we might want to loop through all subsets of the array. If there is a subset whose sum is equal to `half of the sum`, then return `true`. This can be achieved with a `backtracking algorithm`, but after seeing the constraint `nums.length <= 200`, we can estimate that the program will time out. -- This problem can be solved using the `0/1 knapsack problem` algorithm. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Pattern of "0/1 Knapsack Problem" - -The typical "0/1 knapsack problem" means that each "item" can only be used once to fill the "knapsack". "Items" have "weight" and "value" attributes. Find the maximum value of "items" that can be stored in the "knapsack". - -Its characteristics are: there is a **set of numbers**, each number can only be used once, and through some calculation, **another number** is obtained. The question can also be turned into whether it can be obtained? How many variations are there? And so on. - -Because "0/1 Knapsack Problem" belongs to "Dynamic Programming", I will explain it in the pattern of "Dynamic Programming". - -1. Determine what each value of the array `dp` represents. - - Prefer **one-dimensional rolling array** because the code is concise. - - Determine what is "item" and what is "knapsack". - - If `dp[j]` is a boolean value, then `dp[j]` indicates whether the `sum` of the first `i` items can get `j`. - - If `dp[j]` is a numerical value, then `dp[j]` indicates the maximum (or minimum) value that `dp[j]` can reach using the first `i` items. - -2. Initialize the value of the array `dp`. - - Determine the size of the "knapsack". It is necessary to add 1 to the size of the knapsack, that is, insert `dp[0]` as the starting point, which is convenient for understanding and reference. - - `dp[0]` sometimes needs special treatment. -3. According to an example, fill in the `dp` grid data "in order". - - First in the outer loop, **traverse the items**. - - Then in the inner loop, **traverse the knapsack size**. - - When traversing the knapsack size, since `dp[j]` depends on `dp[j]` and `dp[j - weights[i]]`, we should traverse the `dp` array **from right to left**. - - Please think about whether it is possible to traverse the `dp` array from `left to right`? -4. According to the `dp` grid data, derive the "recursive formula". - - If `dp[j]` is a boolean value: - - ```cpp - dp[j] = dp[j] || dp[j - items[i]] - ``` - - If `dp[j]` is a numeric value: - - ```cpp - dp[j] = min_or_max(dp[j], dp[j - weights[i]] + values[i]) - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[j]` - - `dp[j]` represents whether it is possible to `sum` the first `i` `nums` to get `j`. - - `dp[j]` is a boolean. - -2. Determine the `dp` array's initial value - - Use an example: - - ``` - nums = [1,5,11,5], so 'half of the sum' is 11. - The `size` of the knapsack is `11 + 1`, and the `items` are `nums`. - So after initialization, the 'dp' array would be: - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F # dp - # 1 - # 5 - # 11 - # 5 - ``` - - `dp[0]` is set to `true`, indicating that an empty knapsack can be achieved by not putting any items in it. In addition, it is used as the starting value, and the subsequent `dp[j]` will depend on it. If it is `false`, all values of `dp[j]` will be `false`. - - `dp[j] = false (j != 0)`, indicating that it is impossible to get `j` with no `nums`. -3. Fill in the `dp` grid data "in order" according to an example. - - ``` - 1. Use the first num '1'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F # dp - ``` - - ``` - 2. Use the second num '5'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F - # 5 T T F F F T T F F F F F - ``` - - ``` - 3. Use the third num '11'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F - # 5 T T F F F T T F F F F F - # 11 T T F F F T T F F F F T - ``` - - ``` - 3. Use the last num '5'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F - # 5 T T F F F T T F F F F F - # 11 T T F F F T T F F F F T - # 5 T T F F F T T F F F T T # dp - ``` -4. Based on the `dp` grid data, derive the "recursive formula". - - ```cpp - dp[j] = dp[j] || dp[j - nums[i]] - ``` - -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(n * sum/2)`. -- Space complexity: `O(sum/2)`. - -## Python - -```python -class Solution: - def canPartition(self, nums: List[int]) -> bool: - sum_ = sum(nums) - - if sum_ % 2 == 1: - return False - - dp = [False] * ((sum_ // 2) + 1) - dp[0] = True - - for num in nums: - # If not traversing in reverse order, the newly assigned value `dp[j]` will act as `dp[j - num]` later, - # then the subsequent `dp[j]` will be affected. But each `num` can only be used once! - j = len(dp) - 1 - while j >= num: - dp[j] = dp[j] or dp[j - num] - j -= 1 - - return dp[-1] -``` - -## C# - -```csharp -public class Solution -{ - public bool CanPartition(int[] nums) - { - int sum = nums.Sum(); - - if (sum % 2 == 1) - return false; - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (var num in nums) - { - for (var j = dp.GetUpperBound(0); j >= num; j--) - { - dp[j] = dp[j] || dp[j - num]; - } - } - - return dp.Last(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canPartition(vector& nums) { - auto sum = reduce(nums.begin(), nums.end()); - - if (sum % 2 == 1) { - return false; - } - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto num : nums) { - for (auto j = dp.size() - 1; j >= num; j--) { - dp[j] = dp[j] || dp[j - num]; - } - } - - return dp.back(); - } -}; -``` - -## Java - -```java -class Solution { - public boolean canPartition(int[] nums) { - var sum = IntStream.of(nums).sum(); - - if (sum % 2 == 1) { - return false; - } - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var num : nums) { - for (var j = dp.length - 1; j >= num; j--) { - dp[j] = dp[j] || dp[j - num]; - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript - -```javascript -var canPartition = function (nums) { - const sum = _.sum(nums) - - if (sum % 2 == 1) { - return false - } - - const dp = Array(sum / 2 + 1).fill(false) - dp[0] = true - - for (const num of nums) { - for (let j = dp.length - 1; j >= num; j--) { - dp[j] = dp[j] || dp[j - num] - } - } - - return dp.at(-1) -}; -``` - -## Go - -```go -func canPartition(nums []int) bool { - sum := 0 - for _, num := range nums { - sum += num - } - - if sum % 2 == 1 { - return false - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, num := range nums { - for j := len(dp) - 1; j >= num; j-- { - dp[j] = dp[j] || dp[j - num] - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby - -```ruby -def can_partition(nums) - sum = nums.sum - - return false if sum % 2 == 1 - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - nums.each do |num| - (num...dp.size).reverse_each do |j| - dp[j] = dp[j] || dp[j - num] - end - end - - dp[-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -In solution 1, the traversal order is **from right to left** which really matters. - -During the interview, you need to remember it. Is there any way to not worry about the traversal order? - -
Click to view the answer

As long as you copy the original `dp` and reference the value of the copy, you don't have to worry about the original `dp` value being modified.

- -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Complexity - -- Time complexity: `O(n * sum/2)`. -- Space complexity: `O(n * sum/2)`. - -## Python - -```python -class Solution: - def canPartition(self, nums: List[int]) -> bool: - sum_ = sum(nums) - - if sum_ % 2 == 1: - return False - - dp = [False] * ((sum_ // 2) + 1) - dp[0] = True - - for num in nums: - # Make a copy of the 'dp' that has not been modified to eliminate distractions. - dc = dp.copy() - - for j in range(num, len(dp)): # any order is fine - dp[j] = dc[j] or dc[j - num] # Use 'dc' instead of 'dp' because 'dp' will be modified. - - return dp[-1] -``` - -## C# - -```csharp -public class Solution -{ - public bool CanPartition(int[] nums) - { - int sum = nums.Sum(); - - if (sum % 2 == 1) - return false; - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (var num in nums) - { - var dc = (bool[])dp.Clone(); - - for (var j = num; j < dp.Length; j++) - { - dp[j] = dc[j] || dc[j - num]; - } - } - - return dp.Last(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canPartition(vector& nums) { - auto sum = reduce(nums.begin(), nums.end()); - - if (sum % 2 == 1) { - return false; - } - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto num : nums) { - auto dc = dp; - - for (auto j = num; j < dp.size(); j++) { - dp[j] = dc[j] || dc[j - num]; - } - } - - return dp.back(); - } -}; -``` - -## Java - -```java -class Solution { - public boolean canPartition(int[] nums) { - var sum = IntStream.of(nums).sum(); - - if (sum % 2 == 1) { - return false; - } - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var num : nums) { - var dc = dp.clone(); - - for (var j = num; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - num]; - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript - -```javascript -var canPartition = function (nums) { - const sum = _.sum(nums) - - if (sum % 2 == 1) { - return false - } - - const dp = Array(sum / 2 + 1).fill(false) - dp[0] = true - - for (const num of nums) { - const dc = [...dp] - - for (let j = num; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - num] - } - } - - return dp.at(-1) -}; -``` - -## Go - -```go -func canPartition(nums []int) bool { - sum := 0 - for _, num := range nums { - sum += num - } - - if sum % 2 == 1 { - return false - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, num := range nums { - dc := slices.Clone(dp) - - for j := num; j < len(dp); j++ { - dp[j] = dc[j] || dc[j - num] - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby - -```ruby -def can_partition(nums) - sum = nums.sum - - return false if sum % 2 == 1 - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - nums.each do |num| - dc = dp.clone - - (num...dp.size).each do |j| - dp[j] = dc[j] || dc[j - num] - end - end - - dp[-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [416. Partition Equal Subset Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/416-partition-equal-subset-sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/42-trapping-rain-water.md b/en/1-1000/42-trapping-rain-water.md deleted file mode 100644 index 153b6f4..0000000 --- a/en/1-1000/42-trapping-rain-water.md +++ /dev/null @@ -1,263 +0,0 @@ -# 42. Trapping Rain Water (Monotonic Stack) -LeetCode link: [42. Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) - -## LeetCode problem description -Given `n` non-negative integers representing an elevation map where the width of each bar is `1`, compute how much water it can trap after raining. - -### Example 1 -![](../../images/examples/42_1.png) -``` -Input: height = [0,1,0,2,1,0,1,3,2,1,2,1] -Output: 6 - -Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. -In this case, 6 units of rain water (blue section) are being trapped. -``` - -### Example 2 -``` -Input: height = [4,2,0,3,2,5] -Output: 9 -``` - -### Constraints -- `n == height.length` -- `1 <= n <= 2 * 10000` -- `0 <= height[i] <= 100000` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -This solution will follow **Monotonic Stack**'s common rule: **only calculating when `pop()` is happening**. - -This common rule can be applied to calculating result for **most** of the **Monotonic Stack** problems. - -![](../../images/42.png) - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Java -```java -class Solution { - public int trap(int[] heights) { - var result = 0; - var indexStack = new Stack(); - - for (var i = 0; i < heights.length; i++) { - while (!indexStack.empty() && heights[indexStack.peek()] <= heights[i]) { - var poppedIndex = indexStack.pop(); - - if (indexStack.empty()) { - break; - } - - var leftHeight = heights[indexStack.peek()]; - var rightHeight = heights[i]; - var heightGap = Math.min(leftHeight, rightHeight) - heights[poppedIndex]; - var width = i - indexStack.peek() - 1; - result += heightGap * width; - } - - indexStack.push(i); - } - - return result; - } -} -``` - -## Python -```python -class Solution: - def trap(self, heights: List[int]) -> int: - result = 0 - index_stack = [] - - for i, height in enumerate(heights): - while index_stack and heights[index_stack[-1]] <= height: - popped_index = index_stack.pop() - - if not index_stack: - break - - left_height = heights[index_stack[-1]] - right_height = height - height_gap = min(left_height, right_height) - heights[popped_index] - width = i - index_stack[-1] - 1 - result += height_gap * width - - index_stack.append(i) - - return result -``` - -![](../../images/42.png) - -## C++ -```cpp -class Solution { -public: - int trap(vector& heights) { - auto result = 0; - stack index_stack; - - for (auto i = 0; i < heights.size(); i++) { - auto previous_height = 0; - - while (!index_stack.empty() && heights[index_stack.top()] <= heights[i]) { - auto popped_index = index_stack.top(); - index_stack.pop(); - - if (index_stack.empty()) { - break; - } - - auto left_height = heights[index_stack.top()]; - auto right_height = heights[i]; - auto height_gap = min(left_height, right_height) - heights[popped_index]; - auto width = i - index_stack.top() - 1; - result += height_gap * width; - } - - index_stack.push(i); - } - - return result; - } -}; -``` - -## JavaScript -```javascript -var trap = function (heights) { - let result = 0 - const indexStack = [] - - heights.forEach((height, i) => { - while (indexStack.length > 0 && heights[indexStack.at(-1)] <= height) { - const poppedIndex = indexStack.pop() - - if (indexStack.length === 0) { - break - } - - const leftHeight = heights[indexStack.at(-1)] - const rightHeight = heights[i] - const heightGap = Math.min(leftHeight, rightHeight) - heights[poppedIndex] - const width = i - indexStack.at(-1) - 1 - result += heightGap * width - } - - indexStack.push(i) - }) - - return result -}; -``` - -![](../../images/42.png) - -## C# -```c# -public class Solution -{ - public int Trap(int[] heights) - { - int result = 0; - var indexStack = new Stack(); - - for (var i = 0; i < heights.Length; i++) - { - while (indexStack.Count > 0 && heights[indexStack.Peek()] <= heights[i]) - { - int poppedIndex = indexStack.Pop(); - - if (indexStack.Count == 0) - { - break; - } - - int leftHeight = heights[indexStack.Peek()]; - int rightHeight = heights[i]; - int heightGap = Math.Min(leftHeight, rightHeight) - heights[poppedIndex]; - int width = i - indexStack.Peek() - 1; - result += heightGap * width; - } - - indexStack.Push(i); - } - - return result; - } -} -``` - -## Go -```go -func trap(heights []int) int { - result := 0 - indexStack := []int{} - - for i, height := range heights { - for len(indexStack) > 0 && heights[indexStack[len(indexStack) - 1]] <= height { - poppedIndex := indexStack[len(indexStack) - 1] - indexStack = indexStack[:len(indexStack) - 1] - - if len(indexStack) == 0 { - break - } - - leftIndex := indexStack[len(indexStack) - 1] - leftHeight := heights[leftIndex] - rightHeight := heights[i] - heightGap := min(leftHeight, rightHeight) - heights[poppedIndex] - width := i - leftIndex - 1 - result += heightGap * width - } - - indexStack = append(indexStack, i) - } - - return result -} -``` - -![](../../images/42.png) - -## Ruby -```ruby -def trap(heights = []) - result = 0 - index_stack = [] - - heights.each_with_index do |height, i| - while !index_stack.empty? && heights[index_stack.last] <= height - popped_index = index_stack.pop - - break if index_stack.empty? - - left_height = heights[index_stack.last] - right_height = heights[i] - height_gap = [ left_height, right_height ].min - heights[popped_index] - width = i - index_stack.last - 1 - result += height_gap * width - end - - index_stack << i - end - - result -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/433-minimum-genetic-mutation.md b/en/1-1000/433-minimum-genetic-mutation.md deleted file mode 100644 index dd490ca..0000000 --- a/en/1-1000/433-minimum-genetic-mutation.md +++ /dev/null @@ -1,217 +0,0 @@ -# 433. Minimum Genetic Mutation - Best Practices of LeetCode Solutions -LeetCode link: [433. Minimum Genetic Mutation](https://leetcode.com/problems/minimum-genetic-mutation), difficulty: **Medium**. - -## LeetCode description of "433. Minimum Genetic Mutation" -A gene string can be represented by an 8-character long string, with choices from `A`, `C`, `G`, and `T`. - -Suppose we need to investigate a mutation from a gene string `startGene` to a gene string `endGene` where one mutation is defined as one single character changed in the gene string. - -* For example, `"AACCGGTT" --> "AACCGGTA"` is one mutation. - -There is also a gene bank `bank` that records all the valid gene mutations. A gene must be in `bank` to make it a valid gene string. - -Given the two gene strings `startGene` and `endGene` and the gene bank `bank`, return _the minimum number of mutations needed to mutate from `startGene` to `endGene`_. If there is no such a mutation, return `-1`. - -Note that the starting point is assumed to be valid, so it might not be included in the bank. - -### [Example 1] -**Input**: `startGene = "AACCGGTT", endGene = "AACCGGTA", bank = ["AACCGGTA"]` - -**Output**: `1` - -### [Example 2] -**Input**: `startGene = "AACCGGTT", endGene = "AAACGGTA", bank = ["AACCGGTA","AACCGCTA","AAACGGTA"]` - -**Output**: `2` - -### [Constraints] -- `0 <= bank.length <= 10` -- `startGene.length == endGene.length == bank[i].length == 8` -- `startGene`, `endGene`, and `bank[i]` consist of only the characters `['A', 'C', 'G', 'T']`. - -## Intuition 1 -We can think of this problem as a shortest path problem on a graph: there are `4^8` vertices (strings `'AAAAAAAA'` to `'TTTTTTTT'`), and there is an edge between two vertices if they differ in one character, and if *both* vertices are in `bank`. - -So this issue can be solved by **Breadth-First Search** on a undirected graph. - -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **Breadth-First Search** can be thought of as visiting vertices in rounds and rounds. Actually, whenever you see a question is about - getting `minimum number` of something of a graph, `Breadth-First Search` would probably help. - -* `Breadth-First Search` emphasizes first-in-first-out, so a **queue** is needed. - -### Approach 1: Breadth-First Search Algorithm -1. `Breadth-First Search` a graph means traversing **from near to far**, from `circle 1` to `circle N`. Each `circle` is a round of iteration. -1. So through `Breadth-First Search`, when a word matches `endGene`, the game is over, and we can return the number of **circle** as a result. - -### Complexity -> **N** is the length of `bank`. - -* Time: `O((8 * 4) * N)`. -* Space: `O(N)`. - -## Approach 2: A* (A-Star) Search Algorithm - -**A-Star Search Algorithm** can be used to greatly improve the performance of **Breadth-First Search Algorithm**. - -Please view detailed **A-Star Algorithm** at [752. Open the Lock](./752-open-the-lock.md). - -Bellow has code using _A-Star Search Algorithm_ in Python. - -## Python -### Approach 1: Breadth-First Search (way 1) -```python -class Solution: - def minMutation(self, start_gene: str, end_gene: str, bank: List[str]) -> int: - if not end_gene in bank: - return -1 - - self.end_gene = end_gene - self.bank = set(bank) - self.queue = deque([start_gene]) # difference 1 - result = 0 - - while self.queue: - result += 1 # difference 2 - queue_size = len(self.queue) - - for i in range(queue_size): # difference 3 - gene = self.queue.popleft() - - if self.mutate_one(gene): - return result - - return -1 - - def mutate_one(self, gene): # difference 4 - for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: - if gene[i] == char: - continue - - mutation = f'{gene[:i]}{char}{gene[i + 1:]}' - - if mutation == self.end_gene: - return True - - if mutation in self.bank: - self.queue.append(mutation) - self.bank.remove(mutation) -``` - -### Approach 1: Breadth-First Search (way 2 by adding `mutated_count` in queue's item) -```python -class Solution: - def minMutation(self, start_gene: str, end_gene: str, bank: List[str]) -> int: - if not end_gene in bank: - return -1 - - self.bank = set(bank) - self.end_gene = end_gene - self.queue = deque([(start_gene, 0)]) # difference 1 - - while self.queue: - gene, mutated_count = self.queue.popleft() # difference 2 - - if self.mutate_one(gene, mutated_count): - return mutated_count + 1 - - return -1 - - def mutate_one(self, gene, mutated_count): # difference 3 - for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: - if gene[i] == char: - continue - - mutation = f'{gene[:i]}{char}{gene[i + 1:]}' - - if mutation == self.end_gene: - return True - - if mutation in self.bank: - self.queue.append((mutation, mutated_count + 1)) - self.bank.remove(mutation) -``` - -### Approach 2: A* (A-Star) Search Algorithm -```python -import heapq - - -class Solution: - def minMutation(self, start_gene: str, end_gene: str, bank: List[str]) -> int: - if not end_gene in bank: - return -1 - - self.end_gene = end_gene - bank = set(bank) - priority_queue = [(self.distance(start_gene), start_gene, 0)] # difference 1 - - while priority_queue: - _, gene, mutated_count = heapq.heappop(priority_queue) # difference 2 - - for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: - if gene[i] == char: - continue - - mutation = f'{gene[:i]}{char}{gene[i + 1:]}' - - if mutation == end_gene: - return mutated_count + 1 - - if mutation in bank: - heapq.heappush( - priority_queue, - (self.distance(mutation), mutation, mutated_count + 1) - ) # difference 3 - bank.remove(mutation) - - return -1 - - def distance(self, gene): # difference 4 - result = 0 - - for i in range(8): - if gene[i] != self.end_gene[i]: - result += 1 - - return result -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/454-4sum-ii.md b/en/1-1000/454-4sum-ii.md deleted file mode 100644 index 97609db..0000000 --- a/en/1-1000/454-4sum-ii.md +++ /dev/null @@ -1,279 +0,0 @@ -# 454. 4Sum II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [454. 4Sum II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/454-4sum-ii) for a better experience! - -LeetCode link: [454. 4Sum II](https://leetcode.com/problems/4sum-ii), difficulty: **Medium**. - -## LeetCode description of "454. 4Sum II" - -Given four integer arrays `nums1`, `nums2`, `nums3`, and `nums4` all of length `n`, return the number of tuples `(i, j, k, l)` such that: - -- `0 <= i, j, k, l < n` -- `nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0` - -### [Example 1] - -**Input**: `nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]` - -**Output**: `2` - -**Explanation**: - -

The two tuples are:

- -
    -
  1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
  2. -
  3. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
  4. -
- - -### [Example 2] - -**Input**: `nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]` - -**Output**: `1` - -### [Constraints] - -- `n == nums1.length` -- `n == nums2.length` -- `n == nums3.length` -- `n == nums4.length` -- `1 <= n <= 200` -- `-2^28 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2^28` - -## Intuition - -1. Because the final requirement is to take one number from each group of numbers, the four groups of numbers can be split into **two groups of two**. -2. Count the number of each `sum`. Use `Map` to store, `key` is `sum`, `value` is `count`. -3. Iterate over `nums3` and `nums4`, if `-(num3 + num4)` exists in `keys` of `Map`, then `count` is included in the total. - -## Step by Step Solutions - -1. Count the number of each `sum`. Use `Map` to store, `key` is `sum`, `value` is `count`. - - ```python - num_to_count = defaultdict(int) - - for num1 in nums1: - for num2 in nums2: - num_to_count[num1 + num2] += 1 - ``` - -2. Iterate over `nums3` and `nums4`, if `-(num3 + num4)` exists in `keys` of `Map`, then `count` is included in the total. - - ```python - result = 0 - - for num3 in nums3: - for num4 in nums4: - result += num_to_count[-(num3 + num4)] - - return result - ``` - -## Complexity - -- Time complexity: `O(N * N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { - var numToCount = new HashMap(); - - for (var num1 : nums1) { - for (var num2 : nums2) { - numToCount.put( - num1 + num2, - numToCount.getOrDefault(num1 + num2, 0) + 1 - ); - } - } - - var result = 0; - - for (var num3 : nums3) { - for (var num4 : nums4) { - result += numToCount.getOrDefault(-(num3 + num4), 0); - } - } - - return result; - } -} -``` - -## Python - -```python -# from collections import defaultdict - -class Solution: - def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int: - num_to_count = defaultdict(int) - - for num1 in nums1: - for num2 in nums2: - num_to_count[num1 + num2] += 1 - - result = 0 - - for num3 in nums3: - for num4 in nums4: - result += num_to_count[-(num3 + num4)] - - return result -``` - -## JavaScript - -```javascript -var fourSumCount = function (nums1, nums2, nums3, nums4) { - const numToCount = new Map() - - for (const num1 of nums1) { - for (const num2 of nums2) { - numToCount.set(num1 + num2, (numToCount.get(num1 + num2) || 0) + 1) - } - } - - let result = 0 - - for (const num3 of nums3) { - for (const num4 of nums4) { - result += numToCount.get(-(num3 + num4)) || 0 - } - } - - return result -}; -``` - -## C# - -```csharp -public class Solution -{ - public int FourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) - { - var numToCount = new Dictionary(); - - foreach (int num1 in nums1) - { - foreach (int num2 in nums2) - { - numToCount[num1 + num2] = numToCount.GetValueOrDefault(num1 + num2, 0) + 1; - } - } - - int result = 0; - - foreach (int num3 in nums3) - { - foreach (int num4 in nums4) - { - result += numToCount.GetValueOrDefault(-(num3 + num4), 0); - } - } - - return result; - } -} -``` - -## Ruby - -```ruby -def four_sum_count(nums1, nums2, nums3, nums4) - num_to_count = Hash.new(0) - - nums1.each do |num1| - nums2.each do |num2| - num_to_count[num1 + num2] += 1 - end - end - - result = 0 - - nums3.each do |num3| - nums4.each do |num4| - result += num_to_count[-(num3 + num4)] - end - end - - result -end -``` - -## Go - -```go -func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int { - // Create map to store sum frequencies from first two arrays - sumCount := make(map[int]int) - - // Calculate all possible sums from nums1 and nums2 - for _, num1 := range nums1 { - for _, num2 := range nums2 { - sumCount[num1 + num2]++ - } - } - - result := 0 - // Check complementary sums from nums3 and nums4 - for _, num3 := range nums3 { - for _, num4 := range nums4 { - // Add count of complementary sum that would make total zero - result += sumCount[-(num3 + num4)] - } - } - - return result -} -``` - -## C++ - -```cpp -class Solution { -public: - int fourSumCount(vector& nums1, vector& nums2, vector& nums3, vector& nums4) { - // Store sum frequencies from first two arrays - unordered_map sumCount; - - // Calculate all possible sums from nums1 and nums2 - for (int num1 : nums1) { - for (int num2 : nums2) { - sumCount[num1 + num2]++; - } - } - - int result = 0; - // Check complementary sums from nums3 and nums4 - for (int num3 : nums3) { - for (int num4 : nums4) { - // Add occurrences of required complement sum - result += sumCount[-(num3 + num4)]; - } - } - - return result; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [454. 4Sum II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/454-4sum-ii). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/459-repeated-substring-pattern.md b/en/1-1000/459-repeated-substring-pattern.md deleted file mode 100644 index e55dacb..0000000 --- a/en/1-1000/459-repeated-substring-pattern.md +++ /dev/null @@ -1,232 +0,0 @@ -# 459. Repeated Substring Pattern - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [459. Repeated Substring Pattern - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/459-repeated-substring-pattern) for a better experience! - -LeetCode link: [459. Repeated Substring Pattern](https://leetcode.com/problems/repeated-substring-pattern), difficulty: **Easy**. - -## LeetCode description of "459. Repeated Substring Pattern" - -Given a string `s`, check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. - -### [Example 1] - -**Input**: `s = "abcabcabcabc"` - -**Output**: `true` - -**Explanation**: - -

It is the substring "abc" four times or the substring "abcabc" twice.

- - -### [Example 2] - -**Input**: `s = "aba"` - -**Output**: `false` - -### [Constraints] - -- `1 <= s.length <= 10000` -- `s` consists of lowercase English letters. - -## Intuition - -The key to solving this problem is to see clearly that if `s` can be obtained by repeating the substring, then the starting letter of the substring must be `s[0]`. - -Once you understand this, the scope of substring investigation is greatly narrowed. - -## Complexity - -- Time complexity: `O(N * N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def repeatedSubstringPattern(self, s: str) -> bool: - for i in range(1, int(len(s) / 2) + 1): - if len(s) % i == 0 and s[:i] * int(len(s) / i) == s: - return True - - return False -``` - -## JavaScript - -```javascript -var repeatedSubstringPattern = function (s) { - for (let i = 1; i <= s.length / 2; i++) { - if (s.length % i != 0) { - continue - } - - if (s.slice(0, i).repeat(s.length / i) == s) { - return true - } - } - - return false -}; -``` - -## Go - -```go -func repeatedSubstringPattern(s string) bool { - n := len(s) - - for i := 1; i <= n/2; i++ { - if n%i == 0 { - substring := s[:i] - repeated := strings.Repeat(substring, n/i) - - if repeated == s { - return true - } - } - } - - return false -} -``` - -## C++ - -```cpp -class Solution { -public: - bool repeatedSubstringPattern(string s) { - int n = s.length(); - - for (int i = 1; i <= n / 2; i++) { - if (n % i != 0) { - continue; - } - - string pattern = s.substr(0, i); - string repeated = ""; - - for (int j = 0; j < n / i; j++) { - repeated += pattern; - } - - if (repeated == s) { - return true; - } - } - - return false; - } -}; -``` - -## Java - -```java -class Solution { - public boolean repeatedSubstringPattern(String s) { - int n = s.length(); - - for (var i = 1; i <= n / 2; i++) { - if (n % i != 0) { - continue; - } - - var pattern = s.substring(0, i); - var repeated = new StringBuilder(); - - // Simply concatenate the pattern multiple times - for (var j = 0; j < n / i; j++) { - repeated.append(pattern); - } - - // Compare the constructed string with the original string - if (repeated.toString().equals(s)) { - return true; - } - } - - return false; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public bool RepeatedSubstringPattern(string s) - { - int n = s.Length; - - for (int i = 1; i <= n / 2; i++) - { - if (n % i != 0) - { - continue; - } - - // Get the potential substring pattern - string pattern = s.Substring(0, i); - StringBuilder repeated = new StringBuilder(); - - // Simply concatenate the pattern multiple times - for (int j = 0; j < n / i; j++) - { - repeated.Append(pattern); - } - - // Compare the constructed string with the original string - if (repeated.ToString() == s) - { - return true; - } - } - - return false; - } -} -``` - -## Ruby - -```ruby -# @param {String} s -# @return {Boolean} -def repeated_substring_pattern(s) - n = s.length - - (1..n / 2).each do |i| - next unless n % i == 0 - - pattern = s[0...i] - repeated = "" - - # Simply concatenate the pattern multiple times - (0...(n / i)).each do - repeated += pattern - end - - # Compare the constructed string with the original string - return true if repeated == s - end - - false -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [459. Repeated Substring Pattern - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/459-repeated-substring-pattern). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/463-island-perimeter.md b/en/1-1000/463-island-perimeter.md deleted file mode 100644 index dde4d77..0000000 --- a/en/1-1000/463-island-perimeter.md +++ /dev/null @@ -1,215 +0,0 @@ -# LeetCode 463. Island Perimeter's Solution -LeetCode link: [463. Island Perimeter](https://leetcode.com/problems/island-perimeter) - -## LeetCode problem description -You are given `row x col` `grid` representing a map where `grid[i][j] = 1` represents land and `grid[i][j] = 0` represents water. - -Grid cells are connected **horizontally/vertically** (not diagonally). The `grid` is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells). - -The island doesn't have "lakes", meaning the water inside isn't connected to the water around the island. One cell is a square with side length 1. The grid is rectangular, width and height don't exceed 100. Determine the perimeter of the island. - -### Example 1 -![](../../images/examples/463_1.png) -``` -Input: grid = [ - [0,1,0,0], - [1,1,1,0], - [0,1,0,0], - [1,1,0,0] -] -Output: 16 -Explanation: The perimeter is the 16 yellow stripes in the image above. -``` - -### Example 2 -``` -Input: grid = [[1]] -Output: 4 -``` - -### Example 3 -``` -Input: grid = [[1,0]] -Output: 4 -``` - -### Constraints -- `row == grid.length` -- `col == grid[i].length` -- `1 <= row, col <= 100` -- `grid[i][j]` is `0` or `1`. -- There is exactly one island in `grid`. - -## Intuition and Approach 1: Straightforward -1. To calculate the perimeter of an island, we simply add up the number of water-adjacent edges of all water-adjacent lands. -2. When traversing the grid, once land is found, the number of its adjacent water edges is calculated. - -## Intuition 2 -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph has only one **connected components** (island). - -## Approach 2: Depth-First Search the Island (complex way) -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Depth-First Search** (DFS) and **Breadth-First Search** (BFS). - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. Here I will provide the `Recursive` solution. - * If you want to know **Depth-First Search** `Iterative` solution, please see [200. Number of Islands (Depth-First Search by Iteration)](200-number-of-islands-2.md). - * If you want to know **Breadth-First Search** solution, please see [200. Number of Islands (Breadth-First Search)](200-number-of-islands-3.md). - * Mark each found land as `8` which represents `visited`. Visited lands don't need to be visited again. -1. To calculate the perimeter of an island, we simply add up the number of water-adjacent edges of all water-adjacent lands. -1. To solve this problem, you don't really need to use `DFS` or `BFS`, but mastering `DFS` and `BFS` is absolutely necessary. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(1)`. - -## Python -### Solution 1: Straightforward -```python -class Solution: - def __init__(self): - self.grid = None - - def islandPerimeter(self, grid: List[List[int]]) -> int: - self.grid = grid - perimeter = 0 - - for i in range(len(grid)): - for j in range(len(grid[0])): - if grid[i][j] == 1: - perimeter += self.water_side_count(i, j) - - return perimeter - - def water_side_count(self, i, j): - side_count = 0 - - for a, b in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0), - ]: - m = i + a - n = j + b - - if m < 0 or n < 0 or m >= len(self.grid) or n >= len(self.grid[0]) \ - or self.grid[m][n] == 0: - side_count += 1 - - return side_count -``` - -### Solution 2: Depth-First Search the Island (complex way) -```python -class Solution: - def __init__(self): - self.perimeter = 0 - self.grid = None - - def islandPerimeter(self, grid: List[List[int]]) -> int: - self.grid = grid - - for i, row in enumerate(self.grid): - for j, value in enumerate(row): - if value == 1: - self.depth_first_search(i, j) - - return self.perimeter - - def depth_first_search(self, i, j): - if i < 0 or i >= len(self.grid): - return - - if j < 0 or j >= len(self.grid[0]): - return - - if self.grid[i][j] != 1: - return - - self.grid[i][j] = 8 - - self.perimeter += self.water_edges(i, j) - - self.depth_first_search(i - 1, j) - self.depth_first_search(i, j + 1) - self.depth_first_search(i + 1, j) - self.depth_first_search(i, j - 1) - - def water_edges(self, i, j): - result = 0 - result += self.water_edge(i - 1, j) - result += self.water_edge(i, j + 1) - result += self.water_edge(i + 1, j) - result += self.water_edge(i, j - 1) - return result - - def water_edge(self, i, j): - if i < 0 or i >= len(self.grid): - return 1 - - if j < 0 or j >= len(self.grid[0]): - return 1 - - if self.grid[i][j] == 0: - return 1 - - return 0 -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/474-ones-and-zeroes.md b/en/1-1000/474-ones-and-zeroes.md deleted file mode 100644 index 64d7109..0000000 --- a/en/1-1000/474-ones-and-zeroes.md +++ /dev/null @@ -1,476 +0,0 @@ -# 474. Ones and Zeroes - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [474. Ones and Zeroes - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/474-ones-and-zeroes) for a better experience! - -LeetCode link: [474. Ones and Zeroes](https://leetcode.com/problems/ones-and-zeroes), difficulty: **Medium**. - -## LeetCode description of "474. Ones and Zeroes" - -You are given an array of binary strings `strs` and two integers `m` and `n`. - -Return the size of the largest subset of `strs` such that there are **at most** `m` `0`'s and `n` `1`'s in the subset. - -A set `x` is a **subset** of a set `y` if all elements of `x` are also elements of `y`. - -### [Example 1] - -**Input**: `strs = ["10","0001","111001","1","0"], m = 5, n = 3` - -**Output**: `4` - -**Explanation**: - -

The largest subset with at most 5 0's and 3 1's is {"10", "0001", "1", "0"}, so the answer is 4.
-Other valid but smaller subsets include {"0001", "1"} and {"10", "1", "0"}.
-{"111001"} is an invalid subset because it contains 4 1's, greater than the maximum of 3.

- - -### [Example 2] - -**Input**: `strs = ["10","0","1"], m = 1, n = 1` - -**Output**: `2` - -**Explanation**: - -

The largest subset is {"0", "1"}, so the answer is 2.

- - -### [Constraints] - -- `1 <= strs.length <= 600` -- `1 <= strs[i].length <= 100` -- `'strs[i]' consists only of digits '0' and '1'` -- `1 <= m, n <= 100` - -## Intuition - -This question is difficult. It is recommended to complete a simple question of the same type first [416. Partition Equal Subset Sum](416-partition-equal-subset-sum.md). - -- After completing 416, you will find that this question requires solving the `0/1 Knapsack Problem` in two dimensions. -- The solution is to first solve the problem in one dimension and then expand it to two dimensions. -- It is no need to draw a grid that considers both dimensions together, that's too complicated. Let's first **only** consider the quantity limit of `0`. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Pattern of "0/1 Knapsack Problem" - -The typical "0/1 knapsack problem" means that each "item" can only be used once to fill the "knapsack". "Items" have "weight" and "value" attributes. Find the maximum value of "items" that can be stored in the "knapsack". - -Its characteristics are: there is a **set of numbers**, each number can only be used once, and through some calculation, **another number** is obtained. The question can also be turned into whether it can be obtained? How many variations are there? And so on. - -Because "0/1 Knapsack Problem" belongs to "Dynamic Programming", I will explain it in the pattern of "Dynamic Programming". - -1. Determine what each value of the array `dp` represents. - - Prefer **one-dimensional rolling array** because the code is concise. - - Determine what is "item" and what is "knapsack". - - If `dp[j]` is a boolean value, then `dp[j]` indicates whether the `sum` of the first `i` items can get `j`. - - If `dp[j]` is a numerical value, then `dp[j]` indicates the maximum (or minimum) value that `dp[j]` can reach using the first `i` items. - -2. Initialize the value of the array `dp`. - - Determine the size of the "knapsack". It is necessary to add 1 to the size of the knapsack, that is, insert `dp[0]` as the starting point, which is convenient for understanding and reference. - - `dp[0]` sometimes needs special treatment. -3. According to an example, fill in the `dp` grid data "in order". - - First in the outer loop, **traverse the items**. - - Then in the inner loop, **traverse the knapsack size**. - - When traversing the knapsack size, since `dp[j]` depends on `dp[j]` and `dp[j - weights[i]]`, we should traverse the `dp` array **from right to left**. - - Please think about whether it is possible to traverse the `dp` array from `left to right`? -4. According to the `dp` grid data, derive the "recursive formula". - - If `dp[j]` is a boolean value: - - ```cpp - dp[j] = dp[j] || dp[j - items[i]] - ``` - - If `dp[j]` is a numeric value: - - ```cpp - dp[j] = min_or_max(dp[j], dp[j - weights[i]] + values[i]) - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[j]` - - Since we are only considering the zero count constraint for now, we can use a one-dimensional `dp` array. - - `items` is `strs`, `backpack` is `max_zero_count`. - - `dp[j]` represents the maximum number of strings that can be selected with at most `j` zeros. - - `dp[j]` is an integer. - -2. Determine the `dp` array's initial value - - Use an example, example 1: `Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3`. - - After initialization: - ```python - max_zero_count = m - dp = [0] * (max_zero_count + 1) - ``` - - `dp[0] = 0`, indicating that with no zeros, we can select 0 strings. - - `dp[j] = 0` as the initial value because we will use `max` to increase them later. - -3. According to an example, fill in the `dp` grid data "in order". - - Let's analyze the example step by step: - - ``` - # Initial state - # 0 1 2 3 4 5 - # 0 0 0 0 0 0 - - # After processing "10" (1 zero) - # 0 1 2 3 4 5 - # 0 1 1 1 1 1 - - # After processing "0001" (3 zeros) - # 0 1 2 3 4 5 - # 0 1 1 1 2 2 - - # After processing "111001" (2 zeros) - # 0 1 2 3 4 5 - # 0 1 1 2 2 2 - - # After processing "1" (0 zeros) - # 0 1 2 3 4 5 - # 0 2 2 3 3 3 - - # After processing "0" (1 zero) - # 0 1 2 3 4 5 - # 0 2 3 3 4 4 - ``` -4. According to the `dp` grid data, derive the "recursive formula". - - ```cpp - dp[j] = max(dp[j], dp[j - zero_count] + 1) - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - The code that only considers the quantity limit of `0` is: - - ```python - class Solution: - def findMaxForm(self, strs: List[str], max_zero_count: int, n: int) -> int: - dp = [0] * (max_zero_count + 1) - - for string in strs: - zero_count = count_zero(string) - - for j in range(len(dp) - 1, zero_count - 1, -1): # must iterate in reverse order! - dp[j] = max(dp[j], dp[j - zero_count] + 1) - - return dp[-1] - - - def count_zero(string): - zero_count = 0 - - for bit in string: - if bit == '0': - zero_count += 1 - - return zero_count - ``` - -#### Now, you can consider another dimension: the quantity limit of `1`. - -It should be handled similarly to `0` but in another dimension. Please see the complete code below. - -## Complexity - -- Time complexity: `O(N * M * Len)`. -- Space complexity: `O(N * M)`. - -## Python - -```python -class Solution: - def findMaxForm(self, strs: List[str], max_zero_count: int, max_one_count: int) -> int: - dp = [[0] * (max_one_count + 1) for _ in range(max_zero_count + 1)] - - for string in strs: - zero_count, one_count = count_zero_one(string) - - for i in range(len(dp) - 1, zero_count - 1, -1): - for j in range(len(dp[0]) - 1, one_count - 1, -1): - dp[i][j] = max(dp[i][j], dp[i - zero_count][j - one_count] + 1) - - return dp[-1][-1] - - -def count_zero_one(string): - zero_count = 0 - one_count = 0 - - for bit in string: - if bit == '0': - zero_count += 1 - else: - one_count += 1 - - return zero_count, one_count -``` - -## C++ - -```cpp -class Solution { -public: - int findMaxForm(vector& strs, int max_zero_count, int max_one_count) { - vector> dp(max_zero_count + 1, vector(max_one_count + 1, 0)); - - for (auto& str : strs) { - auto zero_count = 0; - auto one_count = 0; - - for (auto bit : str) { - if (bit == '0') { - zero_count++; - } else { - one_count++; - } - } - - for (auto i = max_zero_count; i >= zero_count; i--) { - for (auto j = max_one_count; j >= one_count; j--) { - dp[i][j] = max(dp[i][j], dp[i - zero_count][j - one_count] + 1); - } - } - } - - return dp[max_zero_count][max_one_count]; - } -}; -``` - -## Java - -```java -class Solution { - public int findMaxForm(String[] strs, int maxZeroCount, int maxOneCount) { - var dp = new int[maxZeroCount + 1][maxOneCount + 1]; - - for (var str : strs) { - var zeroCount = 0; - var oneCount = 0; - - for (var bit : str.toCharArray()) { - if (bit == '0') { - zeroCount++; - } else { - oneCount++; - } - } - - for (var i = maxZeroCount; i >= zeroCount; i--) { - for (var j = maxOneCount; j >= oneCount; j--) { - dp[i][j] = Math.max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1); - } - } - } - - return dp[maxZeroCount][maxOneCount]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public int FindMaxForm(string[] strs, int maxZeroCount, int maxOneCount) - { - var dp = new int[maxZeroCount + 1, maxOneCount + 1]; - - foreach (var str in strs) - { - var (zeroCount, oneCount) = CountZeroOne(str); - - for (var i = maxZeroCount; i >= zeroCount; i--) - { - for (var j = maxOneCount; j >= oneCount; j--) - { - dp[i, j] = Math.Max(dp[i, j], dp[i - zeroCount, j - oneCount] + 1); - } - } - } - - return dp[maxZeroCount, maxOneCount]; - } - - (int, int) CountZeroOne(string str) - { - var zeroCount = 0; - var oneCount = 0; - - foreach (var bit in str) - { - if (bit == '0') - { - zeroCount++; - } - else - { - oneCount++; - } - } - - return (zeroCount, oneCount); - } -} -``` - -## JavaScript - -```javascript -var findMaxForm = function (strs, maxZeroCount, maxOneCount) { - const dp = Array(maxZeroCount + 1).fill().map( - () => Array(maxOneCount + 1).fill(0) - ) - - for (const str of strs) { - const [zeroCount, oneCount] = countZeroOne(str) - - for (let i = dp.length - 1; i >= zeroCount; i--) { - for (let j = dp[0].length - 1; j >= oneCount; j--) { - dp[i][j] = Math.max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1) - } - } - } - - return dp.at(-1).at(-1) -}; - -function countZeroOne(str) { - let zeroCount = 0 - let oneCount = 0 - - for (const bit of str) { - if (bit === '0') { - zeroCount++ - } else { - oneCount++ - } - } - - return [zeroCount, oneCount] -} -``` - -## Go - -```go -func findMaxForm(strs []string, maxZeroCount int, maxOneCount int) int { - dp := make([][]int, maxZeroCount + 1) - for i := range dp { - dp[i] = make([]int, maxOneCount + 1) - } - - for _, str := range strs { - zeroCount, oneCount := countZeroOne(str) - - for i := len(dp) - 1; i >= zeroCount; i-- { - for j := len(dp[0]) - 1; j >= oneCount; j-- { - dp[i][j] = max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1) - } - } - } - - return dp[maxZeroCount][maxOneCount] -} - -func countZeroOne(str string) (int, int) { - zeroCount := 0 - oneCount := 0 - - for _, bit := range str { - if bit == '0' { - zeroCount++ - } else { - oneCount++ - } - } - - return zeroCount, oneCount -} -``` - -## Ruby - -```ruby -def find_max_form(strs, max_zero_count, max_one_count) - dp = Array.new(max_zero_count + 1) do - Array.new(max_one_count + 1, 0) - end - - strs.each do |string| - zero_count, one_count = count_zero_one(string) - - (zero_count...dp.size).reverse_each do |i| - (one_count...dp[0].size).reverse_each do |j| - dp[i][j] = [ dp[i][j], dp[i - zero_count][j - one_count] + 1 ].max - end - end - end - - dp[-1][-1] -end - -def count_zero_one(string) - zero_count = 0 - one_count = 0 - - string.each_char do |bit| - if bit == '0' - zero_count += 1 - else - one_count += 1 - end - end - - [ zero_count, one_count ] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [474. Ones and Zeroes - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/474-ones-and-zeroes). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/49-group-anagrams.md b/en/1-1000/49-group-anagrams.md deleted file mode 100644 index a82cb68..0000000 --- a/en/1-1000/49-group-anagrams.md +++ /dev/null @@ -1,110 +0,0 @@ -# 49. Group Anagrams - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [49. Group Anagrams - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/49-group-anagrams) for a better experience! - -LeetCode link: [49. Group Anagrams](https://leetcode.com/problems/group-anagrams), difficulty: **Medium**. - -## LeetCode description of "49. Group Anagrams" - -Given an array of strings `strs`, group the **anagrams** together. You can return the answer in **any order**. - -> An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, using all the original letters exactly once. - -### [Example 1] - -**Input**: `strs = ["eat", "tea", "tan", "ate", "nat", "bat"]` - -**Output**: `[["bat"],["nat","tan"],["ate","eat","tea"]]` - -### [Example 2] - -**Input**: `strs = [""]` - -**Output**: `[[""]]` - -### [Example 3] - -**Input**: `strs = ["a"]` - -**Output**: `[["a"]]` - -### [Constraints] - -- `1 <= strs.length <= 10^4` -- `0 <= strs[i].length <= 100` -- `strs[i]` consists of lowercase English letters. - -## Intuition - -- Two strings, `bat` and `atb`, what is the fastest way to know that they are anagrams? - -
Click to view the answer

Sort each string in alphabetical order, and then compare the sorted strings. If they are equal, then they are anagrams.

- -- But after sorting, the original string is not taken into account, and the result is the grouping of the original string. How to solve it? - -
Click to view the answer

Use tuples, that is, put the alphabetically sorted string and the original string in a tuple, like this: `("abt", "bat")`.

- -- All that remains to do is to group this tuple array. What is the easiest way to group? - -
Click to view the answer

Use `Map`, `key` is the alphabetically sorted string, and value is the array of the original string.

- -## Complexity - -> M = string.length - -- Time complexity: `O(N * M * logM)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def groupAnagrams(self, strs: List[str]) -> List[List[str]]: - pairs = [(''.join(sorted(string)), string) for string in strs] - - ordered_to_original = defaultdict(list) - - for ordered, original in pairs: - ordered_to_original[ordered].append(original) - - return list(ordered_to_original.values()) -``` - -## Ruby - -```ruby -# @param {String[]} strs -# @return {String[][]} -def group_anagrams(strs) - pairs = strs.map { |string| [ string.chars.sort.join, string ] } - - ordered_to_original = Hash.new([]) - - pairs.each do |ordered, original| - ordered_to_original[ordered] += [original] - end - - ordered_to_original.values -end - -# Or solution 2: More concise way - -# @param {String[]} strs -# @return {String[][]} -def group_anagrams(strs) - strs.group_by { |string| string.chars.sort }.values -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [49. Group Anagrams - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/49-group-anagrams). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/494-target-sum.md b/en/1-1000/494-target-sum.md deleted file mode 100644 index 160560f..0000000 --- a/en/1-1000/494-target-sum.md +++ /dev/null @@ -1,341 +0,0 @@ -# 494. Target Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [494. Target Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/494-target-sum) for a better experience! - -LeetCode link: [494. Target Sum](https://leetcode.com/problems/target-sum), difficulty: **Medium**. - -## LeetCode description of "494. Target Sum" - -You are given an integer array `nums` and an integer `target`. - -You want to build an **expression** out of nums by adding one of the symbols `+` and `-` before each integer in nums and then concatenate all the integers. - -- For example, if `nums = [2, 1]`, you can add a `+` before 2 and a `-` before `1` and concatenate them to build the expression `+2-1`. - -Return the number of different **expressions** that you can build, which evaluates to `target`. - -### [Example 1] - -**Input**: `nums = [1,1,1,1,1], target = 3` - -**Output**: `5` - -**Explanation**: - -

-1 + 1 + 1 + 1 + 1 = 3
-+1 - 1 + 1 + 1 + 1 = 3
-+1 + 1 - 1 + 1 + 1 = 3
-+1 + 1 + 1 - 1 + 1 = 3
-+1 + 1 + 1 + 1 - 1 = 3

- - -### [Example 2] - -**Input**: `nums = [1], target = 1` - -**Output**: `1` - -### [Constraints] - -- `1 <= nums.length <= 20` -- `0 <= nums[i] <= 1000` -- `0 <= sum(nums[i]) <= 1000` -- `-1000 <= target <= 1000` - -## Intuition - -This problem is quite difficult if you have not solved similar problems before. So before you start working on this question, it is recommended that you first work on another relatively simple question [416. Partition Equal Subset Sum](416-partition-equal-subset-sum.md) that is similar to this one. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[j]` - - `dp[j]` represents that by using the **first** `i` nums, the **number** of different **expressions** that you can build, which evaluates to `j`. - - `dp[j]` is an **integer**. -2. Determine the `dp` array's initial value - - Use an example. We didn't use the `Example 1: Input: nums = [1,1,1,1,1], target = 3` because it is too special and is not a good example for deriving a formula. - - I made up an example: `nums = [1,2,1,2], target = 4`. - - First, determine the `size` of the knapsack. - - The `target` value may be very small, such as `0`, so it alone cannot determine the `size` of the knapsack. - - The sum of `nums` should also be taken into account to fully cover all knapsack sizes. - - `target` may be negative, but considering that `+` and `-` are added to `num` arbitrarily, the `dp[j]` should be symmetrical around `0`. So the result of negative `target` `dp[target]` is equal to `dp[abs(target)]`. - - So the `size` of the knapsack can be `max(sum(nums), target) + 1`. - - Second, determine what are the `items`. The `items` are the `nums` in this problem. - - ``` - So after initialization, the 'dp' array would be: - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 # dp - # 1 - # 2 - # 1 - # 2 - ``` - - `dp[0]` is set to `1`, indicating that an empty knapsack can be achieved by not using any `nums`. In addition, it is used as the starting value, and the subsequent `dp[j]` will depend on it. If it is `0`, all values of `dp[j]` will be `0`. - - `dp[j] = 0 (j != 0)`, indicating that it is impossible to get `j` with no `nums`. -3. According to an example, fill in the `dp` grid data "in order". - - ``` - 1. Use the first num '1'. - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 # dp - # 2 - # 1 - # 2 - ``` - ``` - 2. Use the second num '2'. - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 - # 2 0 1 0 1 0 0 0 - # 1 - # 2 - ``` - ``` - 3. Use the third num '1'. - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 - # 2 0 1 0 1 0 0 0 - # 1 2 0 2 0 1 0 0 - # 2 - ``` - ``` - 4. Use the fourth num '2'. - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 - # 2 0 1 0 1 0 0 0 - # 1 2 0 2 0 1 0 0 - # 2 4 0 3 0 2 0 1 # dp - ``` -4. According to the `dp` grid data, derive the "recursive formula". - - ```java - dp[j] = dp[abs(j - nums[i])] + dp[j + nums[i]] - ``` - - If `j < nums[i]`, `dp[j - nums[i]]` will raise `array index out of range` exception. So we use the `dp[abs(j - num)]` which is equal to it, because the `dp[j]` are symmetrical around `0`, such as `dp[-j]` equals to `dp[j]` (`-j` is an imaginary index). - - When `j + nums[i] >= dp.length`, `dp[j + nums[i]]` must be `0` to prevent interference. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(n * sum)`. -- Space complexity: `O(n * sum)`. - -## C# - -```csharp -public class Solution -{ - public int FindTargetSumWays(int[] nums, int target) - { - target = Math.Abs(target); - - var dp = new int[Math.Max(nums.Sum(), target) + 1]; - dp[0] = 1; - - foreach (var num in nums) - { - var dc = (int[])dp.Clone(); - - for (var j = 0; j < dp.Length; j++) - { - dp[j] = dc[Math.Abs(j - num)] + (j + num < dp.Length ? dc[j + num] : 0); - } - } - - return dp[target]; - } -} -``` - -## Python - -```python -class Solution: - def findTargetSumWays(self, nums: List[int], target: int) -> int: - target = abs(target) - - dp = [0] * (max(sum(nums), target) + 1) - dp[0] = 1 - - for num in nums: - dc = dp.copy() - - for j in range(len(dp)): - dp[j] = dc[abs(j - num)] + (dc[j + num] if j + num < len(dp) else 0) - - return dp[target] -``` - -## C++ - -```cpp -class Solution { -public: - int findTargetSumWays(vector& nums, int target) { - auto sum = reduce(nums.begin(), nums.end()); - target = abs(target); - - auto dp = vector(max(sum, target) + 1); - dp[0] = 1; - - for (auto num : nums) { - auto dc = dp; - - for (auto j = 0; j < dp.size(); j++) { - dp[j] = dc[abs(j - num)] + (j + num < dp.size() ? dc[j + num] : 0); - } - } - - return dp[target]; - } -}; -``` - -## Java - -```java -class Solution { - public int findTargetSumWays(int[] nums, int target) { - var sum = IntStream.of(nums).sum(); - target = Math.abs(target); - - var dp = new int[Math.max(sum, target) + 1]; - dp[0] = 1; - - for (var num : nums) { - var dc = dp.clone(); - - for (var j = 0; j < dp.length; j++) { - dp[j] = dc[Math.abs(j - num)] + (j + num < dp.length ? dc[j + num] : 0); - } - } - - return dp[target]; - } -} -``` - -## JavaScript - -```javascript -var findTargetSumWays = function (nums, target) { - target = Math.abs(target) - - const dp = Array(Math.max(_.sum(nums), target) + 1).fill(0) - dp[0] = 1 - - for (const num of nums) { - const dc = [...dp] - - for (let j = 0; j < dp.length; j++) { - dp[j] = dc[Math.abs(j - num)] + (j + num < dp.length ? dc[j + num] : 0) - } - } - - return dp[target] -}; -``` - -## Go - -```go -func findTargetSumWays(nums []int, target int) int { - sum := 0 - for _, num := range nums { - sum += num - } - target = int(math.Abs(float64(target))) - - dp := make([]int, max(sum, target) + 1) - dp[0] = 1 - - for _, num := range nums { - dc := slices.Clone(dp) - - for j := 0; j < len(dp); j++ { - addition := 0 - if j + num < len(dp) { - addition = dc[j + num] - } - dp[j] = dc[int(math.Abs(float64((j - num))))] + addition - } - } - - return dp[target] -} -``` - -## Ruby - -```ruby -def find_target_sum_ways(nums, target) - target = target.abs - - dp = Array.new([ nums.sum, target ].max + 1, 0) - dp[0] = 1 - - nums.each do |num| - dc = dp.clone - - dp.each_with_index do |_, j| - dp[j] = dc[(j - num).abs] + (j + num < dp.size ? dc[j + num] : 0) - end - end - - dp[target] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [494. Target Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/494-target-sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/496-next-greater-element-i.md b/en/1-1000/496-next-greater-element-i.md deleted file mode 100644 index a74e834..0000000 --- a/en/1-1000/496-next-greater-element-i.md +++ /dev/null @@ -1,415 +0,0 @@ -# 496. Next Greater Element I -LeetCode link: [496. Next Greater Element I](https://leetcode.com/problems/next-greater-element-i/) - -## LeetCode problem description -The next greater element of some element `x` in an array is the first greater element that is to the right of `x` in the same array. - -You are given two distinct 0-indexed integer arrays `nums1` and `nums2`, where `nums1` is a subset of `nums2`. - -For each `0 <= i < nums1.length`, find the index `j` such that `nums1[i] == nums2[j]` and determine the next greater element of `nums2[j]` in `nums2`. If there is no next greater element, then the answer for this query is `-1`. - -Return an array `ans` of length `nums1.length` such that `ans[i]` is the next greater element as described above. - -``` ------------------------------------------------------------------------------------------------ -[Example 1] - -Input: nums1 = [4,1,2], nums2 = [1,3,4,2] -Output: [-1,3,-1] - -Explanation: The next greater element for each value of nums1 is as follows: -- 4 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. -- 1 is underlined in nums2 = [1,3,4,2]. The next greater element is 3. -- 2 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. ------------------------------------------------------------------------------------------------ -[Example 2] - -Input: nums1 = [2,4], nums2 = [1,2,3,4] -Output: [3,-1] - -Explanation: The next greater element for each value of nums1 is as follows: -- 2 is underlined in nums2 = [1,2,3,4]. The next greater element is 3. -- 4 is underlined in nums2 = [1,2,3,4]. There is no next greater element, so the answer is -1. ------------------------------------------------------------------------------------------------ -[Constraints] - -1 <= nums1.length <= nums2.length <= 1000 -0 <= nums1[i], nums2[i] <= 10000 -All integers in 'nums1' and 'nums2' are unique. -All the integers of 'nums1' also appear in 'nums2'. ------------------------------------------------------------------------------------------------ -``` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -#### Brute force solution -* Time: `O(n * m)`. -* Space: `O(n)`. - -#### Monotonic stack solution -* Time: `O(n + m)`. -* Space: `O(n)`. - -## Java -### Brute force solution -```java -class Solution { - public int[] nextGreaterElement(int[] nums1, int[] nums2) { - var results = new int[nums1.length]; - Arrays.fill(results, -1); - - for (var i = 0; i < nums1.length; i++) { - var found = false; - - for (var num2 : nums2) { - if (found && num2 > nums1[i]) { - results[i] = num2; - break; - } - - if (nums1[i] == num2) { - found = true; - } - } - } - - return results; - } -} -``` - -### Monotonic stack solution -```java -class Solution { - public int[] nextGreaterElement(int[] nums1, int[] nums2) { - var numToGreaterNum = new HashMap(); - var stack = new Stack(); - - for (var num : nums2) { - while (!stack.empty() && stack.peek() < num) { - numToGreaterNum.put(stack.pop(), num); - } - - stack.push(num); - } - - var result = new int[nums1.length]; - - for (var i = 0; i < nums1.length; i++) { - result[i] = numToGreaterNum.getOrDefault(nums1[i], -1); - } - - return result; - } -} -``` - -## Python -### Brute force solution -```python -class Solution: - def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]: - results = [-1] * len(nums1) - - for i, num1 in enumerate(nums1): - found = False - - for num2 in nums2: - if found and num2 > num1: - results[i] = num2 - break - - if num1 == num2: - found = True - - return results -``` - -### Monotonic stack solution -```python -class Solution: - def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]: - num_to_greater_num = defaultdict(int) - stack = [] - - for num in nums2: - while stack and num > stack[-1]: - num_to_greater_num[stack.pop()] = num - - stack.append(num) - - return [num_to_greater_num[num] or -1 for num in nums1] -``` - -## C++ -### Brute force solution -```cpp -class Solution { -public: - vector nextGreaterElement(vector& nums1, vector& nums2) { - vector results(nums1.size(), -1); - - for (auto i = 0; i < nums1.size(); i++) { - auto found = false; - - for (auto num2 : nums2) { - if (found && num2 > nums1[i]) { - results[i] = num2; - break; - } - - if (nums1[i] == num2) { - found = true; - } - } - } - - return results; - } -}; -``` - -### Monotonic stack solution -```cpp -class Solution { -public: - vector nextGreaterElement(vector& nums1, vector& nums2) { - unordered_map num_to_greater_num; - stack monotonic_stack; - - for (auto num : nums2) { - while (!monotonic_stack.empty() && monotonic_stack.top() < num) { - num_to_greater_num[monotonic_stack.top()] = num; - monotonic_stack.pop(); - } - - monotonic_stack.push(num); - } - - vector result; - - for (auto num : nums1) { - result.emplace_back( - num_to_greater_num.contains(num) ? num_to_greater_num[num] : -1 - ); - } - - return result; - } -}; -``` - -## JavaScript -### Brute force solution -```javascript -var nextGreaterElement = function (nums1, nums2) { - const results = Array(nums1.length).fill(-1) - - nums1.forEach((num1, i) => { - let found = false - - for (const num2 of nums2) { - if (found && num2 > num1) { - results[i] = num2 - break - } - - if (num1 == num2) { - found = true - } - } - }) - - return results -}; -``` - -### Monotonic stack solution -```javascript -var nextGreaterElement = function (nums1, nums2) { - const numToGreaterNum = {} - const stack = [] - - nums2.forEach((num) => { - while (stack.length > 0 && stack.at(-1) < num) { - numToGreaterNum[stack.pop()] = num - } - - stack.push(num) - }) - - return nums1.map((num) => numToGreaterNum[num] || -1) -}; -``` - -## C# -### Brute force solution -```c# -public class Solution -{ - public int[] NextGreaterElement(int[] nums1, int[] nums2) - { - var results = new int[nums1.Length]; - Array.Fill(results, -1); - - for (var i = 0; i < nums1.Length; i++) - { - bool found = false; - - foreach (var num2 in nums2) - { - if (found && num2 > nums1[i]) - { - results[i] = num2; - break; - } - - if (nums1[i] == num2) - { - found = true; - } - } - } - - return results; - } -} -``` - -### Monotonic stack solution -```c# -public class Solution -{ - public int[] NextGreaterElement(int[] nums1, int[] nums2) - { - var numToGreater = new Dictionary(); - var stack = new Stack(); - - foreach (int num in nums2) - { - while (stack.Count > 0 && stack.Peek() < num) - { - numToGreater[stack.Pop()] = num; - } - - stack.Push(num); - } - - var result = new int[nums1.Length]; - - for (var i = 0; i < nums1.Length; i++) - { - result[i] = numToGreater.GetValueOrDefault(nums1[i], -1); - } - - return result; - } -} -``` - -## Go -### Brute force solution -```go -func nextGreaterElement(nums1 []int, nums2 []int) []int { - results := slices.Repeat([]int{-1}, len(nums1)) - - for i, num1 := range nums1 { - found := false - - for _, num2 := range nums2 { - if found && num2 > num1 { - results[i] = num2 - break - } - - if num1 == num2 { - found = true - } - } - } - - return results -} -``` - -### Monotonic stack solution -```go -func nextGreaterElement(nums1 []int, nums2 []int) []int { - numToGreaterNum := map[int]int{} - stack := []int{} - - for _, num := range nums2 { - for (len(stack) > 0 && stack[len(stack) - 1] < num) { - numToGreaterNum[stack[len(stack) - 1]] = num - stack = stack[:len(stack) - 1] - } - - stack = append(stack, num) - } - - results := slices.Repeat([]int{-1}, len(nums1)) - - for i, num1 := range nums1 { - if value, ok := numToGreaterNum[num1]; ok { - results[i] = value - } - } - - return results -} -``` - -## Ruby -### Brute force solution -```ruby -def next_greater_element(nums1, nums2) - results = Array.new(nums1.size, -1) - - nums1.each_with_index do |num1, i| - found = false - - nums2.each do |num2| - if found and num2 > num1 - results[i] = num2 - break - end - - found = true if num1 == num2 - end - end - - results -end -``` - -### Monotonic stack solution -```ruby -def next_greater_element(nums1, nums2) - num_to_greater_num = {} - stack = [] - - nums2.each do |num| - while !stack.empty? && stack.last < num - num_to_greater_num[stack.pop] = num - end - - stack << num - end - - nums1.map { |num| num_to_greater_num[num] || -1 } -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/5-longest-palindromic-substring.md b/en/1-1000/5-longest-palindromic-substring.md deleted file mode 100644 index b013d38..0000000 --- a/en/1-1000/5-longest-palindromic-substring.md +++ /dev/null @@ -1,148 +0,0 @@ -# 5. Longest Palindromic Substring - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [5. Longest Palindromic Substring - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/5-longest-palindromic-substring) for a better experience! - -LeetCode link: [5. Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring), difficulty: **Medium**. - -## LeetCode description of "5. Longest Palindromic Substring" - -Given a string `s`, return *the longest palindromic substring in `s`*. - -- A string is **palindromic** if it reads the same forward and backward. -- A **substring** is a contiguous **non-empty** sequence of characters within a string. - -### [Example 1] - -**Input**: `s = "babad"` - -**Output**: `"bab"` - -**Explanation**: `"aba" is also a valid answer.` - -### [Example 2] - -**Input**: `s = "cbbd"` - -**Output**: `"bb"` - -### [Constraints] - -- `1 <= s.length <= 1000` -- `s` consist of only digits and English letters. - -### [Hints] - -
- Hint 1 - How can we reuse a previously computed palindrome to compute a larger palindrome? - - -
- -
- Hint 2 - If “aba” is a palindrome, is “xabax” a palindrome? Similarly is “xabay” a palindrome? - - -
- -
- Hint 3 - Complexity based hint: -If we use brute-force and check whether for every start and end position a substring is a palindrome we have O(n^2) start - end pairs and O(n) palindromic checks. Can we reduce the time for palindromic checks to O(1) by reusing some previous computation. - - -
- -## Intuition - - - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Complexity - -- Time complexity: ``. -- Space complexity: ``. - -## Ruby - -```ruby -# @param {String} s -# @return {String} -def longest_palindrome(s) - longest = s[0] - s = s.chars.join("#") - - s.size.times do |i| - j = 1 - - while j <= i and i + j < s.size - break if s[i - j] != s[i + j] - - if s[i - j] == '#' - j += 1 - next - end - - length = j * 2 + 1 - - if length > longest.size - longest = s[i - j..i + j] - end - - j += 1 - end - end - - longest.gsub('#', '') -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [5. Longest Palindromic Substring - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/5-longest-palindromic-substring). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/503-next-greater-element-ii.md b/en/1-1000/503-next-greater-element-ii.md deleted file mode 100644 index c387faf..0000000 --- a/en/1-1000/503-next-greater-element-ii.md +++ /dev/null @@ -1,226 +0,0 @@ -# 503. Next Greater Element II -LeetCode link: [503. Next Greater Element II](https://leetcode.com/problems/next-greater-element-ii/) - -## LeetCode problem description -Given a circular integer array `nums` (i.e., the next element of `nums[nums.length - 1]` is `nums[0]`), return the **next greater number** for every element in `nums`. - -The **next greater number** of a number `x` is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, return `-1` for this number. -``` ------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [1,2,1] -Output: [2,-1,2] - -Explanation: The first 1's next greater number is 2; -The number 2 can't find next greater number. -The second 1's next greater number needs to search circularly, which is also 2. ------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [1,2,3,4,3] -Output: [2,3,4,-1,4] ------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 10000 --10^9 <= nums[i] <= 10^9 ------------------------------------------------------------------------------------- -``` - -## Solution 1: Brute Force -This problem can be solved using **Brute Force**. But if the `nums.length` is much greater, the solution will time out. -Then We need to use a more efficient algorithm. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * n)`. -* Space: `O(n)`. - -## Solution 2: Monotonic Stack Algorithm (more efficient) -This solution will reduce the time complexity to **O(n)**. - -A similar issue is [Next Greater Element I](496-next-greater-element-i.md), you can read it first. - -Checkout the `Python` section bellow to view the code. - -## Python -### Solution 2: Monotonic Stack -```python -# This is a better test case: -# [2, 5, 3, 2, 4, 1] for `nums` -# [2, 5, 3, 2, 4, 1, 2, 5, 3, 2, 4] for `extended_nums` - -class Solution: - def nextGreaterElements(self, nums: List[int]) -> List[int]: - extended_nums = nums + nums[:-1] - index_stack = [] - result = [-1] * len(extended_nums) - - for i, num in enumerate(extended_nums): - while index_stack and extended_nums[index_stack[-1]] < num: - result[index_stack.pop()] = num - - index_stack.append(i) - - return result[:len(nums)] -``` - -### Solution 1: Brute Force -```python -class Solution: - def nextGreaterElements(self, nums: List[int]) -> List[int]: - results = [-1] * len(nums) - nums2 = nums + nums - - for i, num1 in enumerate(nums): - for j in range(i + 1, len(nums2)): - if nums2[j] > num1: - results[i] = nums2[j] - break - - return results -``` - - -## C# -```c# -public class Solution -{ - public int[] NextGreaterElements(int[] nums) - { - int[] nums2 = [..nums, ..nums]; - var results = new int[nums.Length]; - Array.Fill(results, -1); - - for (var i = 0; i < nums.Length; i++) - { - for (var j = i + 1; j < nums2.Length; j++) - { - if (nums2[j] > nums[i]) - { - results[i] = nums2[j]; - break; - } - } - } - - return results; - } -} -``` - -## Java -```java -class Solution { - public int[] nextGreaterElements(int[] nums) { - var results = new int[nums.length]; - Arrays.fill(results, -1); - - var nums2 = Arrays.copyOf(nums, nums.length * 2); - System.arraycopy(nums, 0, nums2, nums.length, nums.length); - - for (var i = 0; i < nums.length; i++) { - for (var j = i + 1; j < nums2.length; j++) { - if (nums2[j] > nums[i]) { - results[i] = nums2[j]; - break; - } - } - } - - return results; - } -} -``` - -## C++ -```cpp -class Solution { -public: - vector nextGreaterElements(vector& nums) { - vector results(nums.size(), -1); - auto nums2 = nums; - ranges::copy(nums, back_inserter(nums2)); - - for (auto i = 0; i < nums.size(); i++) { - for (auto j = i + 1; j < nums2.size(); j++) { - if (nums2[j] > nums[i]) { - results[i] = nums2[j]; - break; - } - } - } - - return results; - } -}; -``` - -## JavaScript -```javascript -var nextGreaterElements = function (nums) { - const results = Array(nums.length).fill(-1) - const nums2 = [...nums, ...nums] - - for (let i = 0; i < nums.length; i++) { - for (let j = i + 1; j < nums2.length; j++) { - if (nums2[j] > nums[i]) { - results[i] = nums2[j] - break - } - } - } - - return results -}; -``` - -## Go -```go -func nextGreaterElements(nums []int) []int { - results := slices.Repeat([]int{-1}, len(nums)) - nums2 := slices.Repeat(nums, 2) - - for i, num := range nums { - for j := i + 1; j < len(nums2); j++ { - if nums2[j] > num { - results[i] = nums2[j] - break - } - } - } - - return results -} -``` - -## Ruby -```ruby -def next_greater_elements(nums) - results = Array.new(nums.size, -1) - nums2 = nums + nums - - nums.each_with_index do |num, i| - ((i + 1)...nums2.size).each do |j| - if nums2[j] > num - results[i] = nums2[j] - break - end - end - end - - results -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/509-fibonacci-number.md b/en/1-1000/509-fibonacci-number.md deleted file mode 100644 index 69242d1..0000000 --- a/en/1-1000/509-fibonacci-number.md +++ /dev/null @@ -1,611 +0,0 @@ -# 509. Fibonacci Number - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [509. Fibonacci Number - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/509-fibonacci-number) for a better experience! - -LeetCode link: [509. Fibonacci Number](https://leetcode.com/problems/fibonacci-number), difficulty: **Easy**. - -## LeetCode description of "509. Fibonacci Number" - -The **Fibonacci numbers**, commonly denoted `F(n)` form a sequence, called the **Fibonacci sequence**, such that each number is the sum of the two preceding ones, starting from `0` and `1`. That is, - -> F(0) = 0, F(1) = 1 -> F(n) = F(n - 1) + F(n - 2), for n > 1. - -Given `n`, calculate `F(n)`. - -### [Example 1] - -**Input**: `n = 2` - -**Output**: `1` - -**Explanation**: `F(2) = F(1) + F(0) = 1 + 0 = 1` - -### [Example 2] - -**Input**: `n = 3` - -**Output**: `2` - -**Explanation**: `F(3) = F(2) + F(1) = 1 + 1 = 2` - -### [Example 3] - -**Input**: `n = 4` - -**Output**: `3` - -**Explanation**: `F(4) = F(3) + F(2) = 2 + 1 = 3` - -### [Constraints] - -0 <= n <= 30 - -## Intuition 1 - - - -## Pattern of "Recursion" - -Recursion is an important concept in computer science and mathematics, which refers to the method by which a function calls itself **directly or indirectly** in its definition. - -### The core idea of ​​recursion - -- **Self-call**: A function calls itself during execution. -- **Base case**: Equivalent to the termination condition. After reaching the base case, the result can be returned without recursive calls to prevent infinite loops. -- **Recursive step**: The step by which the problem gradually approaches the "base case". - -## Complexity - -> If no Map is added to cache known results, the time complexity will rise to O( 2^N ) - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## C# - -```csharp -public class Solution { - IDictionary numToFibNum = new Dictionary(); - - public int Fib(int n) { - if (n <= 1) { - return n; - } - - if (numToFibNum.ContainsKey(n)) { - return numToFibNum[n]; - } - - numToFibNum[n] = Fib(n - 1) + Fib(n - 2); - - return numToFibNum[n]; - } -} -``` - -## Python - -```python -class Solution: - @cache - def fib(self, n: int) -> int: - if n <= 1: - return n - - return self.fib(n - 1) + self.fib(n - 2) -``` - -## C++ - -```cpp -class Solution { -public: - int fib(int n) { - if (n <= 1) { - return n; - } - - if (num_to_fib_num_.contains(n)) { - return num_to_fib_num_[n]; - } - - num_to_fib_num_[n] = fib(n - 1) + fib(n - 2); - - return num_to_fib_num_[n]; - } - -private: - unordered_map num_to_fib_num_; -}; -``` - -## Java - -```java -class Solution { - var numToFibNum = new HashMap(); - - public int fib(int n) { - if (n <= 1) { - return n; - } - - if (numToFibNum.containsKey(n)) { - return numToFibNum.get(n); - } - - numToFibNum.put(n, fib(n - 1) + fib(n - 2)); - - return numToFibNum.get(n); - } -} -``` - -## JavaScript - -```javascript -const numToFibNum = new Map() - -var fib = function (n) { - if (n <= 1) { - return n - } - - if (numToFibNum.has(n)) { - return numToFibNum.get(n) - } - - numToFibNum.set(n, fib(n - 1) + fib(n - 2)) - - return numToFibNum.get(n) -}; -``` - -## Go - -```go -func fib(m int) int { - numToFibNum := map[int]int{} - - var fibonacci func (int) int - - fibonacci = func (n int) int { - if n <= 1 { - return n - } - - if result, ok := numToFibNum[n]; ok { - return result - } - - numToFibNum[n] = fibonacci(n - 1) + fibonacci(n - 2) - return numToFibNum[n] - } - - return fibonacci(m) -} -``` - -## Ruby - -```ruby -def fib(n) - return n if n <= 1 - - @cache = {} if @cache.nil? - - return @cache[n] if @cache.key?(n) - - @cache[n] = fib(n - 1) + fib(n - 2) - - @cache[n] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - - - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## C# - -```csharp -public class Solution -{ - public int Fib(int n) - { - if (n <= 1) - return n; - - var dp = new int[n + 1]; - dp[1] = 1; - - for (var i = 2; i < dp.Length; i++) - { - dp[i] = dp[i - 1] + dp[i - 2]; - } - - return dp[n]; - } -} -``` - -## Python - -```python -class Solution: - def fib(self, n: int) -> int: - if n == 0: - return 0 - - dp = [0] * (n + 1) - dp[1] = 1 - - for i in range(2, len(dp)): - dp[i] = dp[i - 1] + dp[i - 2] - - return dp[-1] -``` - -## C++ - -```cpp -class Solution { -public: - int fib(int n) { - if (n <= 1) { - return n; - } - - auto dp = vector(n + 1); - dp[1] = 1; - - for (auto i = 2; i < dp.size(); i++) { - dp[i] = dp[i - 1] + dp[i - 2]; - } - - return dp[n]; - } -}; -``` - -## Java - -```java -class Solution { - public int fib(int n) { - if (n <= 1) { - return n; - } - - var dp = new int[n + 1]; - dp[1] = 1; - - for (var i = 2; i < dp.length; i++) { - dp[i] = dp[i - 1] + dp[i - 2]; - } - - return dp[n]; - } -} -``` - -## JavaScript - -```javascript -var fib = function (n) { - if (n <= 1) { - return n - } - - const dp = Array(n + 1).fill(0) - dp[1] = 1 - - for (let i = 2; i < dp.length; i++) { - dp[i] = dp[i - 1] + dp[i - 2] - } - - return dp[n] -}; -``` - -## Go - -```go -func fib(n int) int { - if n == 0 { - return 0 - } - - dp := make([]int, n + 1) - dp[1] = 1 - - for i := 2; i <= n; i++ { - dp[i] = dp[i - 2] + dp[i - 1] - } - - return dp[n] -} -``` - -## Ruby - -```ruby -def fib(n) - return 0 if n == 0 - - dp = Array.new(n + 1, 0) - dp[1] = 1 - - (2...dp.size).each do |i| - dp[i] = dp[i - 1] + dp[i - 2] - end - - dp[-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 3 - - - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## C# - -```csharp -public class Solution -{ - public int Fib(int n) - { - if (n <= 1) - return n; - - int[] dp = [0, 1]; - - for (var i = 2; i <= n; i++) - { - var dc = (int[])dp.Clone(); - - dp[0] = dc[1]; - dp[1] = dc[0] + dc[1]; - } - - return dp[1]; - } -} -``` - -## Python - -```python -class Solution: - def fib(self, n: int) -> int: - if n == 0: - return 0 - - dp = [0, 1] - - for i in range(2, n + 1): - dc = dp.copy() - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - - return dp[1] -``` - -## C++ - -```cpp -class Solution { -public: - int fib(int n) { - if (n <= 1) { - return n; - } - - vector dp = {0, 1}; - - for (auto i = 2; i <= n; i++) { - auto dc = dp; - - dp[0] = dc[1]; - dp[1] = dc[0] + dc[1]; - } - - return dp[1]; - } -}; -``` - -## Java - -```java -class Solution { - public int fib(int n) { - if (n <= 1) { - return n; - } - - int[] dp = {0, 1}; - - for (var i = 2; i <= n; i++) { - var dc = dp.clone(); - - dp[0] = dc[1]; - dp[1] = dc[0] + dc[1]; - } - - return dp[1]; - } -} -``` - -## JavaScript - -```javascript -var fib = function (n) { - if (n <= 1) { - return n - } - - const dp = [0, 1] - - for (let i = 2; i <= n; i++) { - const dc = [...dp] - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - } - - return dp[1] -}; -``` - -## Go - -```go -func fib(n int) int { - if n == 0 { - return 0 - } - - dp := []int{0, 1} - - for i := 2; i <= n; i++ { - dc := slices.Clone(dp) - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - } - - return dp[1] -} -``` - -## Ruby - -```ruby -def fib(n) - return 0 if n == 0 - - dp = [0, 1] - - (2..n).each do |i| - dc = dp.clone - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - end - - dp[1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [509. Fibonacci Number - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/509-fibonacci-number). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/518-coin-change-ii.md b/en/1-1000/518-coin-change-ii.md deleted file mode 100644 index bc1c4cb..0000000 --- a/en/1-1000/518-coin-change-ii.md +++ /dev/null @@ -1,186 +0,0 @@ -# 518. Coin Change II -LeetCode link: [518. Coin Change II](https://leetcode.com/problems/coin-change-ii/) - -## LeetCode problem description -> You are given an integer array `coins` representing coins of different denominations and an integer amount representing a total `amount` of money. - -Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return `0`. - -You may assume that you have an infinite number of each kind of coin. - -The answer is **guaranteed** to fit into a signed 32-bit integer. - -``` -Example 1: - -Input: amount = 5, coins = [1,2,5] -Output: 4 - -Explanation: there are four ways to make up the amount: -5=5 -5=2+2+1 -5=2+1+1+1 -5=1+1+1+1+1 ------------------------------------------------------------------------- - -Example 2: - -Input: amount = 3, coins = [2] -Output: 0 - -Explanation: the amount of 3 cannot be made up just with coins of 2. ------------------------------------------------------------------------- - -Example 3: - -Input: amount = 10, coins = [10] -Output: 1 ------------------------------------------------------------------------- - -Constraints: - -1 <= coins.length <= 300 -1 <= coins[i] <= 5000 -All the values of 'coins' are unique. -0 <= amount <= 5000 -``` - -## Thoughts -It is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int Change(int amount, int[] coins) - { - var dp = new int[amount + 1]; - dp[0] = 1; - - foreach (int coin in coins) - { - for (var j = coin; j < dp.Length; j++) - { - dp[j] += dp[j - coin]; - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def change(self, amount: int, coins: List[int]) -> int: - dp = [0] * (amount + 1) - dp[0] = 1 - - for coin in coins: - for j in range(coin, len(dp)): - dp[j] += dp[j - coin] - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int change(int amount, vector& coins) { - auto dp = vector(amount + 1, 0); - dp[0] = 1; - - for (auto coin : coins) { - for (auto j = coin; j < dp.size(); j++) { - dp[j] += dp[j - coin]; - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int change(int amount, int[] coins) { - var dp = new int[amount + 1]; - dp[0] = 1; - - for (var coin : coins) { - for (var j = coin; j < dp.length; j++) { - dp[j] += dp[j - coin]; - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -```javascript -var change = function (amount, coins) { - const dp = Array(amount + 1).fill(0) - dp[0] = 1 - - for (const coin of coins) { - for (let j = coin; j < dp.length; j++) { - dp[j] += dp[j - coin] - } - } - - return dp.at(-1); -}; -``` - -## Go -```go -func change(amount int, coins []int) int { - dp := make([]int, amount + 1) - dp[0] = 1 - - for _, coin := range coins { - for j := coin; j < len(dp); j++ { - dp[j] += dp[j - coin] - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def change(amount, coins) - dp = Array.new(amount + 1, 0) - dp[0] = 1 - - coins.each do |coin| - (coin...dp.size).each do |j| - dp[j] += dp[j - coin] - end - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/53-maximum-subarray.md b/en/1-1000/53-maximum-subarray.md deleted file mode 100644 index de256f7..0000000 --- a/en/1-1000/53-maximum-subarray.md +++ /dev/null @@ -1,392 +0,0 @@ -# 53. Maximum Subarray - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [53. Maximum Subarray - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/53-maximum-subarray) for a better experience! - -LeetCode link: [53. Maximum Subarray](https://leetcode.com/problems/maximum-subarray), difficulty: **Medium**. - -## LeetCode description of "53. Maximum Subarray" - -Given an integer array `nums`, find the `subarray` with the largest sum, and return its sum. - -### [Example 1] - -**Input**: `nums = [-2,1,-3,4,-1,2,1,-5,4]` - -**Output**: `6` - -**Explanation**: - -

The subarray [4,-1,2,1] has the largest sum 6.

- - -### [Example 2] - -**Input**: `nums = [1]` - -**Output**: `1` - -**Explanation**: `The subarray [1] has the largest sum 1.` - -### [Example 3] - -**Input**: `nums = [5,4,-1,7,8]` - -**Output**: `23` - -**Explanation**: - -

The subarray [5,4,-1,7,8] has the largest sum 23.

- - -### [Constraints] - -- `1 <= nums.length <= 10^5` -- `-10^4 <= nums[i] <= 10^4` - -## Intuition 1 - -- This problem can be solved by using `Greedy Algorithm` (please see `solution 2`), yet here we will use another way. -- For `nums[i]`: - 1. If the `previous sum` is negative, we can discard `previous sum`; - 2. If the `previous sum` is positive, we can add `previous sum` to the `current sum`. -- Therefore, it meets the characteristics of a `dynamic programming` problem. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[i]` - - Imagine that `dp[i]` represents the `largest sum` at index `i`. Is this okay? - mark-detail `dp[i + 1]` cannot be calculated by `dp[i]`. So we have to change the meaning. mark-detail -- How to design it? - mark-detail If `dp[i]` represents the `current sum` at index `i`, `dp[i + 1]` can be calculated by `dp[i]`. Finally, we can see that the `maximum sum` is recorded in the `current sum` array. mark-detail -2. Determine the `dp` array's initial value - - ```ruby - nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - dp = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - ``` -3. Fill in the `dp` grid data "in order" according to an example. - - ```ruby - nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - dp = [-2, 1, N, N, N, N, N, N, N] # N means don't pay attention to it now - dp = [-2, 1, -2, N, N, N, N, N, N] - dp = [-2, 1, -2, 4, N, N, N, N, N] - dp = [-2, 1, -2, 4, 3, N, N, N, N] - dp = [-2, 1, -2, 4, 3, 5, N, N, N] - dp = [-2, 1, -2, 4, 3, 5, 6, N, N] - dp = [-2, 1, -2, 4, 3, 5, 6, 1, N] - dp = [-2, 1, -2, 4, 3, 5, 6, 1, 5] - ``` -4. Based on the `dp` grid data, derive the "recursive formula". - - ```python - dp[i] = max(nums[i], dp[i - 1] + nums[i]) - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(n)`. -- Space complexity: `O(n)`. - -## Python - -```python -class Solution: - def maxSubArray(self, nums: List[int]) -> int: - dp = nums.copy() - - for i in range(1, len(dp)): - dp[i] = max(nums[i], dp[i - 1] + nums[i]) - - return max(dp) -``` - -## Java - -```java -class Solution { - public int maxSubArray(int[] nums) { - var dp = nums.clone(); - - for (var i = 1; i < dp.length; i++) { - dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]); - } - - return IntStream.of(dp).max().getAsInt(); // if you want to beat 99%, refer to C# soluiton's comment - } -} -``` - -## JavaScript - -```javascript -var maxSubArray = function (nums) { - const dp = [...nums] - - for (let i = 1; i < dp.length; i++) { - dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]) - } - - return Math.max(...dp) -}; -``` - -## Go - -```go -func maxSubArray(nums []int) int { - dp := slices.Clone(nums) - - for i := 1; i < len(nums); i++ { - dp[i] = max(nums[i], dp[i - 1] + nums[i]) - } - - return slices.Max(dp) -} -``` - -## Ruby - -```ruby -def max_sub_array(nums) - dp = nums.clone - - (1...dp.size).each do |i| - dp[i] = [ nums[i], dp[i - 1] + nums[i] ].max - end - - dp.max -end -``` - -## C# - -```csharp -public class Solution -{ - public int MaxSubArray(int[] nums) - { - var dp = (int[])nums.Clone(); - - for (var i = 1; i < dp.Length; i++) - { - dp[i] = Math.Max(nums[i], dp[i - 1] + nums[i]); - } - - return dp.Max(); // if you want to beat 99%, you can use a variable to collect the maximum value: `if (dp[i] > result) result = dp[i];` - } -} -``` - -## C++ - -```cpp -class Solution { -public: - int maxSubArray(vector& nums) { - auto dp = nums; - - for (auto i = 1; i < dp.size(); i++) { - dp[i] = max(nums[i], dp[i - 1] + nums[i]); - } - - return *max_element(dp.begin(), dp.end()); - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -- The "greedy" algorithm solution and the "dynamic programming" algorithm solution for this problem are essentially the same, both are "dynamic programming", but the "greedy" algorithm here changes from using the dp one-dimensional array and then reducing one dimension to using only two variables. -- The "greedy" algorithm here can be called "rolling variables". Just like "rolling array (one-dimensional)" corresponds to a two-dimensional array, one dimension can be reduced by rolling. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Python - -```python -class Solution: - def maxSubArray(self, nums: List[int]) -> int: - result = -float('inf') - pre_sum = 0 - - for num in nums: - pre_sum = max(pre_sum + num, num) - result = max(result, pre_sum) - - return result -``` - -## C++ - -```cpp -class Solution { -public: - int maxSubArray(vector& nums) { - int result = INT_MIN; - int pre_sum = 0; - - for (int num : nums) { - pre_sum = max(pre_sum + num, num); - result = max(result, pre_sum); - } - - return result; - } -}; -``` - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer} -def max_sub_array(nums) - result = -Float::INFINITY - pre_sum = 0 - - nums.each do |num| - pre_sum = [pre_sum + num, num].max - result = [result, pre_sum].max - end - - result -end -``` - -## Go - -```go -func maxSubArray(nums []int) int { - result := math.MinInt - preSum := 0 - - for _, num := range nums { - preSum = max(preSum + num, num) - if preSum > result { - result = preSum - } - } - - return result -} -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number} - */ -var maxSubArray = function(nums) { - let result = -Infinity; - let preSum = 0; - - for (const num of nums) { - preSum = Math.max(preSum + num, num); - result = Math.max(result, preSum); - } - - return result; -}; -``` - -## C# - -```csharp -public class Solution -{ - public int MaxSubArray(int[] nums) - { - int result = int.MinValue; - int preSum = 0; - - foreach (int num in nums) - { - preSum = Math.Max(preSum + num, num); - result = Math.Max(result, preSum); - } - - return result; - } -} -``` - -## Java - -```java -class Solution { - public int maxSubArray(int[] nums) { - int result = Integer.MIN_VALUE; - int preSum = 0; - - for (int num : nums) { - preSum = Math.max(preSum + num, num); - result = Math.max(result, preSum); - } - - return result; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [53. Maximum Subarray - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/53-maximum-subarray). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/541-reverse-string-ii.md b/en/1-1000/541-reverse-string-ii.md deleted file mode 100644 index c41f157..0000000 --- a/en/1-1000/541-reverse-string-ii.md +++ /dev/null @@ -1,284 +0,0 @@ -# 541. Reverse String II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [541. Reverse String II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/541-reverse-string-ii) for a better experience! - -LeetCode link: [541. Reverse String II](https://leetcode.com/problems/reverse-string-ii), difficulty: **Easy**. - -## LeetCode description of "541. Reverse String II" - -Given a string `s` and an integer `k`, reverse the first `k` characters for every `2k` characters counting from the start of the string. - -- If there are fewer than `k` characters left, reverse all of them. -- If there are less than `2k` but greater than or equal to `k` characters, then reverse the first `k` characters and leave the other as original. - -### [Example 1] - -**Input**: `s = "abcdefg", k = 2` - -**Output**: `bacdfeg` - -### [Example 2] - -**Input**: `s = "abcd", k = 2` - -**Output**: `bacd` - -### [Constraints] - -- `1 <= s.length <= 10000` -- `s` consists of only lowercase English letters. -- `1 <= k <= 10000` - -## Intuition - -1. The question does not require `reverse in place`, so using a new string `result` as the return value is easier to operate. -2. In the loop, it is more convenient to use `k` as the step value rather than `2k`, because if `2k` is used, `k` must still be used for judgment. -3. It is required to reverse only the first `k` characters of each `2k` characters, so a `boolean` variable `should_reverse` is needed as a judgment condition for whether to reverse. - -## Step by Step Solutions - -1. Use a new string `result` as the return value. In the loop, the step value is `k`. - - ```ruby - result = '' - index = 0 - - while index < s.size - k_chars = s[index...index + k] - result += k_chars - index += k - end - - return result - ``` - -2. Use the Boolean variable `should_reverse` as the judgment condition for whether to reverse, and only reverse the first `k` characters of each `2k` characters. - - ```ruby - result = '' - should_reverse = true # 1 - index = 0 - - while index < s.size - k_chars = s[index...index + k] - - if should_reverse # 2 - result += k_chars.reverse # 3 - else # 4 - result += k_chars - end - - index += k - should_reverse = !should_reverse # 5 - end - - return result - ``` - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def reverseStr(self, s: str, k: int) -> str: - result = '' - should_reverse = True - index = 0 - - while index < len(s): - k_chars = s[index:index + k] - - if should_reverse: - result += k_chars[::-1] - else: - result += k_chars - - index += k - should_reverse = not should_reverse - - return result -``` - -## Java - -```java -class Solution { - public String reverseStr(String s, int k) { - var result = new StringBuffer(); - var shouldReverse = true; - var index = 0; - - while (index < s.length()) { - var kChars = s.substring(index, Math.min(index + k, s.length())); - - if (shouldReverse) { - result.append(new StringBuffer(kChars).reverse()); - } else { - result.append(kChars); - } - - index += k; - shouldReverse = !shouldReverse; - } - - return result.toString(); - } -} -``` - -## JavaScript - -```javascript -var reverseStr = function (s, k) { - let result = '' - let shouldReverse = true - let index = 0 - - while (index < s.length) { - const kChars = s.substr(index, k) - - if (shouldReverse) { - result += [...kChars].reverse().join('') - } else { - result += kChars - } - - index += k - shouldReverse = !shouldReverse - } - - return result -}; -``` - -## C# - -```csharp -public class Solution -{ - public string ReverseStr(string s, int k) - { - string result = ""; - bool shouldReverse = true; - int index = 0; - - while (index < s.Length) - { - string kChars = s[index..Math.Min(index + k, s.Length)]; - - if (shouldReverse) - { - result += new string(kChars.Reverse().ToArray()); - } - else - { - result += kChars; - } - - index += k; - shouldReverse = !shouldReverse; - } - - return result; - } -} -``` - -## Ruby - -```ruby -def reverse_str(s, k) - result = '' - should_reverse = true - index = 0 - - while index < s.size - k_chars = s[index...index + k] - - if should_reverse - result += k_chars.reverse - else - result += k_chars - end - - index += k - should_reverse = !should_reverse - end - - result -end -``` - -## C++ - -```cpp -class Solution { -public: - string reverseStr(string s, int k) { - string result = ""; - bool shouldReverse = true; - int index = 0; - - while (index < s.length()) { - auto kChars = s.substr(index, k); - - if (shouldReverse) { - reverse(kChars.begin(), kChars.end()); - } - - result += kChars; - index += k; - shouldReverse = !shouldReverse; - } - - return result; - } -}; -``` - -## Go - -```go -func reverseStr(s string, k int) string { - var result []rune - shouldReverse := true - index := 0 - - for index < len(s) { - end := index + k - if end > len(s) { - end = len(s) - } - kChars := []rune(s[index:end]) - - if shouldReverse { - for i, j := 0, len(kChars) - 1; i < j; i, j = i + 1, j - 1 { - kChars[i], kChars[j] = kChars[j], kChars[i] - } - } - - result = append(result, kChars...) - index += k - shouldReverse = !shouldReverse - } - - return string(result) -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [541. Reverse String II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/541-reverse-string-ii). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/583-delete-operation-for-two-strings.md b/en/1-1000/583-delete-operation-for-two-strings.md deleted file mode 100644 index c40659e..0000000 --- a/en/1-1000/583-delete-operation-for-two-strings.md +++ /dev/null @@ -1,337 +0,0 @@ -# 583. Delete Operation for Two Strings - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [583. Delete Operation for Two Strings - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/583-delete-operation-for-two-strings) for a better experience! - -LeetCode link: [583. Delete Operation for Two Strings](https://leetcode.com/problems/delete-operation-for-two-strings), difficulty: **Medium**. - -## LeetCode description of "583. Delete Operation for Two Strings" - -Given two strings `word1` and `word2`, return the **minimum** number of **steps** required to make `word1` and `word2` the same. - -In one **step**, you can delete exactly one character in either string. - -### [Example 1] - -**Input**: `word1 = "sea", word2 = "eat"` - -**Output**: `2` - -**Explanation**: - -

You need one step to make "sea" to "ea" and another step to make "eat" to "ea".

- - -### [Example 2] - -**Input**: `word1 = "leetcode", word2 = "etco"` - -**Output**: `4` - -### [Constraints] - -- `1 <= word1.length, word2.length <= 500` -- `word1` and `word2` consist of only lowercase English letters. - -## Intuition - -It is a question of **comparing two strings** which is about dealing with "two swappable arrays". -After doing similar questions many times, we will form the intuition of using `two-dimensional arrays` for dynamic programming. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[i][j]`. - - `dp[i][j]` represents the **minimum** number of steps required to make `word1`'s first `i` letters and `word2`'s first `j` letters the same. - - `dp[i][j]` is an integer. -2. Determine the `dp` array's initial value. - - Use an example: - - ``` - After initialization, the 'dp' array would be: - # e a t - # 0 1 2 3 # dp[0] - # s 1 0 0 0 - # e 2 0 0 0 - # a 3 0 0 0 - ``` - - `dp[0][j] = j`, because `dp[0]` represents the empty string, and the number of steps is just the number of chars to be deleted. - - `dp[i][0] = i`, the reason is the same as the previous line, just viewed in vertical direction. -3. Fill in the `dp` grid data "in order" according to an example. - - ``` - 1. word1 = "s", word2 = "eat" - # e a t - # 0 1 2 3 - # s 1 2 3 4 # dp[1] - ``` - ``` - 2. word1 = "se", word2 = "eat" - # e a t - # 0 1 2 3 - # s 1 2 3 4 - # e 2 1 2 3 - ``` - ``` - 3. word1 = "sea", word2 = "eat" - # e a t - # 0 1 2 3 - # s 1 2 3 4 - # e 2 1 2 3 - # a 3 2 1 2 - ``` -4. Based on the `dp` grid data, derive the "recursive formula". - - ```python - if word1[i - 1] == word2[j - 1] - dp[i][j] = dp[i - 1][j - 1] - else - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1 - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(N * M)`. -- Space complexity: `O(N * M)`. - -## Java - -```java -class Solution { - public int minDistance(String word1, String word2) { - var dp = new int[word1.length() + 1][word2.length() + 1]; - for (var i = 0; i < dp.length; i++) { - dp[i][0] = i; - } - for (var j = 0; j < dp[0].length; j++) { - dp[0][j] = j; - } - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (word1.charAt(i - 1) == word2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1; - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public int MinDistance(string word1, string word2) - { - var dp = new int[word1.Length + 1, word2.Length + 1]; - - for (var i = 0; i < dp.GetLength(0); i++) - dp[i, 0] = i; - - for (var j = 0; j < dp.GetLength(1); j++) - dp[0, j] = j; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (word1[i - 1] == word2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1]; - } - else - { - dp[i, j] = Math.Min(dp[i - 1, j], dp[i, j - 1]) + 1; - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Python - -```python -class Solution: - def minDistance(self, word1: str, word2: str) -> int: - dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)] - for i in range(len(dp)): - dp[i][0] = i - for j in range(len(dp[0])): - dp[0][j] = j - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if word1[i - 1] == word2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1 - - return dp[-1][-1] -``` - -## C++ - -```cpp -class Solution { -public: - int minDistance(string word1, string word2) { - vector> dp(word1.size() + 1, vector(word2.size() + 1)); - for (auto i = 0; i < dp.size(); i++) { - dp[i][0] = i; - } - for (auto j = 0; j < dp[0].size(); j++) { - dp[0][j] = j; - } - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1; - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript - -```javascript -var minDistance = function (word1, word2) { - const dp = Array(word1.length + 1).fill().map( - () => Array(word2.length + 1).fill(0) - ) - dp.forEach((_, i) => { dp[i][0] = i }) - dp[0].forEach((_, j) => { dp[0][j] = j }) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go - -```go -func minDistance(word1 string, word2 string) int { - dp := make([][]int, len(word1) + 1) - for i := range dp { - dp[i] = make([]int, len(word2) + 1) - dp[i][0] = i - } - for j := range dp[0] { - dp[0][j] = j - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if word1[i - 1] == word2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby - -```ruby -def min_distance(word1, word2) - dp = Array.new(word1.size + 1) do - Array.new(word2.size + 1, 0) - end - dp.each_with_index do |_, i| - dp[i][0] = i - end - dp[0].each_with_index do |_, j| - dp[0][j] = j - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if word1[i - 1] == word2[j - 1] - dp[i - 1][j - 1] - else - [ dp[i - 1][j], dp[i][j - 1] ].min + 1 - end - end - end - - dp[-1][-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [583. Delete Operation for Two Strings - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/583-delete-operation-for-two-strings). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/59-spiral-matrix-ii.md b/en/1-1000/59-spiral-matrix-ii.md deleted file mode 100644 index b7fdd84..0000000 --- a/en/1-1000/59-spiral-matrix-ii.md +++ /dev/null @@ -1,416 +0,0 @@ -# 59. Spiral Matrix II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [59. Spiral Matrix II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/59-spiral-matrix-ii) for a better experience! - -LeetCode link: [59. Spiral Matrix II](https://leetcode.com/problems/spiral-matrix-ii), difficulty: **Medium**. - -## LeetCode description of "59. Spiral Matrix II" - -Given a positive integer `n`, generate an `n x n` matrix filled with elements from *1* to *n2* in spiral order. - -### [Example 1] - -![](../../images/examples/59_1.jpg) - -**Input**: `n = 3` - -**Output**: `[[1,2,3],[8,9,4],[7,6,5]]` - -### [Example 2] - -**Input**: `n = 1` - -**Output**: `[[1]]` - -### [Constraints] - -- `1 <= n <= 20` - -## Intuition - -- The difficulty of this question lies in how to get the next position of the current position in a two-dimensional array. - -- You can write a method `get_increment(i, j)`, which is specifically used to get the change between the next position and the current position. - -## Step by Step Solutions - -1. Initialize `increments` and `increment_index`: - - ```python - increments = [(0, 1), (1, 0), (0, -1), (-1, 0)] # (i, j) right, down, left, up - increment_index = 0 - ``` - -2. Core logic: - - ```python - while num <= n * n: - matrix[i][j] = num - num += 1 - - increment = get_increment(i, j) - i += increment[0] - j += increment[1] - ``` - -3. For function `get_increment(i, j)`, it should return a pair like `[0, 1]`. First verify whether the current increment is valid. If not, use the next increment. - - ```python - def get_increment(i, j): - increment = increments[increment_index] - i += increment[0] - j += increment[1] - - if ( - i < 0 or i >= len(matrix) or - j < 0 or j >= len(matrix) or - matrix[i][j] is not None - ): # not valid, use next increment - increment_index += 1 - increment_index %= len(self.increments) - - return increments[increment_index] - ``` - -## Complexity - -- Time complexity: `O(N * N)`. -- Space complexity: `O(N * N)`. - -## Java - -```java -class Solution { - private int[][] matrix; - private int[][] increments = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - private int incrementIndex = 0; - - public int[][] generateMatrix(int n) { - matrix = new int[n][n]; - var i = 0; - var j = 0; - var num = 1; - - while (num <= n * n) { - matrix[i][j] = num; - num++; - - var increment = getIncrement(i, j); - i += increment[0]; - j += increment[1]; - } - - return matrix; - } - - private int[] getIncrement(int i, int j) { - var increment = increments[incrementIndex]; - i += increment[0]; - j += increment[1]; - - if ( - i < 0 || i >= matrix.length || - j < 0 || j >= matrix.length || - matrix[i][j] > 0 - ) { - incrementIndex += 1; - incrementIndex %= increments.length; - } - - return increments[incrementIndex]; - } -} -``` - -## Python - -```python -class Solution: - def __init__(self): - self.matrix = None - self.increments = [(0, 1), (1, 0), (0, -1), (-1, 0)] - self.increment_index = 0 - - def generateMatrix(self, n: int) -> List[List[int]]: - self.matrix = [[None] * n for _ in range(n)] - i = 0 - j = 0 - num = 1 - - while num <= n * n: - self.matrix[i][j] = num - num += 1 - - increment = self.get_increment(i, j) - i += increment[0] - j += increment[1] - - return self.matrix - - def get_increment(self, i, j): - increment = self.increments[self.increment_index] - i += increment[0] - j += increment[1] - - if ( - i < 0 or i >= len(self.matrix) or - j < 0 or j >= len(self.matrix) or - self.matrix[i][j] - ): - self.increment_index += 1 - self.increment_index %= len(self.increments) - - return self.increments[self.increment_index] -``` - -## JavaScript - -```javascript -let matrix -const increments = [[0, 1], [1, 0], [0, -1], [-1, 0]] -let incrementIndex - -var generateMatrix = function (n) { - matrix = Array(n).fill().map(() => Array(n).fill(0)) - incrementIndex = 0 - - let i = 0 - let j = 0 - let num = 1 - - while (num <= n * n) { - matrix[i][j] = num - num++ - - const increment = getIncrement(i, j) - i += increment[0] - j += increment[1] - } - - return matrix -}; - -function getIncrement(i, j) { - const increment = increments[incrementIndex] - i += increment[0] - j += increment[1] - - if ( - i < 0 || i >= matrix.length || - j < 0 || j >= matrix.length || - matrix[i][j] > 0 - ) { - incrementIndex += 1 - incrementIndex %= increments.length - } - - return increments[incrementIndex] -} -``` - -## C# - -```csharp -public class Solution -{ - int[][] matrix; - int[][] increments = { new[] {0, 1}, new[] {1, 0}, new[] {0, -1}, new[] {-1, 0} }; - int incrementIndex = 0; - - public int[][] GenerateMatrix(int n) - { - matrix = new int[n][]; - - for (int k = 0; k < n; k++) - matrix[k] = new int[n]; - - int i = 0; - int j = 0; - int num = 1; - - while (num <= n * n) - { - matrix[i][j] = num; - num++; - - int[] increment = getIncrement(i, j); - i += increment[0]; - j += increment[1]; - } - - return matrix; - } - - int[] getIncrement(int m, int n) - { - int[] increment = increments[incrementIndex]; - int i = m + increment[0]; - int j = n + increment[1]; - - if ( - i < 0 || i >= matrix.GetLength(0) || - j < 0 || j >= matrix.GetLength(0) || - matrix[i][j] > 0 - ) - { - incrementIndex += 1; - incrementIndex %= increments.Length; - } - - return increments[incrementIndex]; - } -} -``` - -## Ruby - -```ruby -def generate_matrix(n) - @matrix = Array.new(n) { Array.new(n) } - @increments = [[0, 1], [1, 0], [0, -1], [-1, 0]] - @increment_index = 0 - - i = 0 - j = 0 - num = 1 - - while num <= n * n - @matrix[i][j] = num - num += 1 - - increment = get_increment(i, j) - i += increment[0] - j += increment[1] - end - - @matrix -end - -private - -def get_increment(i, j) - increment = @increments[@increment_index] - next_i = i + increment[0] - next_j = j + increment[1] - - if next_i < 0 || next_i >= @matrix.size || - next_j < 0 || next_j >= @matrix.size || - @matrix[next_i][next_j] - @increment_index += 1 - @increment_index %= @increments.size - end - - @increments[@increment_index] -end -``` - -## Go - -```go -type spiralMatrix struct { - matrix [][]int - increments [][2]int - incrementIndex int -} - -func (sm *spiralMatrix) getIncrement(i, j int) [2]int { - currentIncrement := sm.increments[sm.incrementIndex] - nextI := i + currentIncrement[0] - nextJ := j + currentIncrement[1] - - if nextI < 0 || nextI >= len(sm.matrix) || - nextJ < 0 || nextJ >= len(sm.matrix) || - sm.matrix[nextI][nextJ] != 0 { - sm.incrementIndex = (sm.incrementIndex + 1) % len(sm.increments) - } - return sm.increments[sm.incrementIndex] -} - -func generateMatrix(n int) [][]int { - sm := &spiralMatrix{ - matrix: make([][]int, n), - increments: [][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, - incrementIndex: 0, - } - - for i := range sm.matrix { - sm.matrix[i] = make([]int, n) - } - - i, j, num := 0, 0, 1 - - for num <= n * n { - sm.matrix[i][j] = num - num++ - - increment := sm.getIncrement(i, j) - i += increment[0] - j += increment[1] - } - - return sm.matrix -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> generateMatrix(int n) { - matrix_ = vector>(n, vector(n, 0)); - increments_ = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - increment_index_ = 0; - - int i = 0; - int j = 0; - int num = 1; - - while (num <= n * n) { - matrix_[i][j] = num; - num++; - - vector increment = getIncrement(i, j); - i += increment[0]; - j += increment[1]; - } - - return matrix_; - } - -private: - vector> matrix_; - vector> increments_; - int increment_index_; - - vector getIncrement(int i, int j) { - vector increment = increments_[increment_index_]; - int next_i = i + increment[0]; - int next_j = j + increment[1]; - - if ( - next_i < 0 || next_i >= matrix_.size() || - next_j < 0 || next_j >= matrix_.size() || - matrix_[next_i][next_j] > 0 - ) { - increment_index_++; - increment_index_ %= increments_.size(); - } - - return increments_[increment_index_]; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [59. Spiral Matrix II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/59-spiral-matrix-ii). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/605-can-place-flowers.md b/en/1-1000/605-can-place-flowers.md deleted file mode 100644 index d8d54a2..0000000 --- a/en/1-1000/605-can-place-flowers.md +++ /dev/null @@ -1,223 +0,0 @@ -# 605. Can Place Flowers - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [605. Can Place Flowers - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/605-can-place-flowers) for a better experience! - -LeetCode link: [605. Can Place Flowers](https://leetcode.com/problems/can-place-flowers), difficulty: **Easy**. - -## LeetCode description of "605. Can Place Flowers" - -You have a long flowerbed in which some of the plots are planted, and some are not. However, flowers cannot be planted in **adjacent** plots. - -Given an integer array `flowerbed` containing `0`'s and `1`'s, where `0` means empty and `1` means not empty, and an integer `n`, return `true` if `n` new flowers can be planted in the `flowerbed` without violating the no-adjacent-flowers rule and `false` otherwise. - -### [Example 1] - -**Input**: `flowerbed = [1,0,0,0,1], n = 1` - -**Output**: `true` - -### [Example 2] - -**Input**: `flowerbed = [1,0,0,0,1], n = 2` - -**Output**: `false` - -### [Constraints] - -- `1 <= flowerbed.length <= 2 * 10^4` -- `flowerbed[i]` is `0` or `1`. -- There are no two adjacent flowers in `flowerbed`. -- `0 <= n <= flowerbed.length` - -## Intuition - -Check each empty plot (`0`). If both adjacent plots are empty (or boundaries), plant a flower (set to `1`) and count. Return `true` if the final count ≥ `n`, otherwise `false`. - -## Step by Step Solutions - -1. Initialize counter `count = 0`. -2. Iterate through each plot: - - If current is `1`, skip. - - If current is `0` and both adjacent are `0` (or boundaries), plant (`1`), increment `count`. -3. Return `count >= n`. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(1)`. - -## Python - -```python -class Solution: - def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: - count = 0 - - for i in range(len(flowerbed)): - if flowerbed[i] == 1: - continue - - if (i == 0 or flowerbed[i - 1] == 0) and \ - (i == len(flowerbed) - 1 or flowerbed[i + 1] == 0): - flowerbed[i] = 1 - count += 1 - - return count >= n -``` - -## Java - -```java -class Solution { - public boolean canPlaceFlowers(int[] flowerbed, int n) { - int count = 0; - - for (int i = 0; i < flowerbed.length; i++) { - if (flowerbed[i] == 1) { - continue; - } - - if ((i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canPlaceFlowers(vector& flowerbed, int n) { - int count = 0; - - for (int i = 0; i < flowerbed.size(); i++) { - if (flowerbed[i] == 1) { - continue; - } - - if ((i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.size() - 1 || flowerbed[i + 1] == 0)) { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; - } -}; -``` - -## JavaScript - -```javascript -var canPlaceFlowers = function(flowerbed, n) { - let count = 0; - - for (let i = 0; i < flowerbed.length; i++) { - if (flowerbed[i] === 1) { - continue; - } - - if ((i === 0 || flowerbed[i - 1] === 0) && - (i === flowerbed.length - 1 || flowerbed[i + 1] === 0)) { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; -}; - -``` - -## Go - -```go -func canPlaceFlowers(flowerbed []int, n int) bool { - count := 0 - - for i := 0; i < len(flowerbed); i++ { - if flowerbed[i] == 1 { - continue - } - - if (i == 0 || flowerbed[i - 1] == 0) && - (i == len(flowerbed) - 1 || flowerbed[i + 1] == 0) { - flowerbed[i] = 1 - count++ - } - } - - return count >= n -} - -``` - -## C# - -```csharp -public class Solution -{ - public bool CanPlaceFlowers(int[] flowerbed, int n) - { - int count = 0; - - for (int i = 0; i < flowerbed.Length; i++) - { - if (flowerbed[i] == 1) - { - continue; - } - - if ((i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.Length - 1 || flowerbed[i + 1] == 0)) - { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; - } -} -``` - -## Ruby - -```ruby -def can_place_flowers(flowerbed, n) - count = 0 - - flowerbed.each_with_index do |plot, i| - next if plot == 1 - - if (i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.length - 1 || flowerbed[i + 1] == 0) - flowerbed[i] = 1 - count += 1 - end - end - - count >= n -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [605. Can Place Flowers - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/605-can-place-flowers). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/674-longest-continuous-increasing-subsequence.md b/en/1-1000/674-longest-continuous-increasing-subsequence.md deleted file mode 100644 index cbbf041..0000000 --- a/en/1-1000/674-longest-continuous-increasing-subsequence.md +++ /dev/null @@ -1,162 +0,0 @@ -# 674. Longest Continuous Increasing Subsequence -LeetCode link: [674. Longest Continuous Increasing Subsequence](https://leetcode.com/problems/longest-continuous-increasing-subsequence/) - -## LeetCode problem description -Given an integer array `nums`, return the length of the **longest strictly increasing subsequence**. - -``` ----------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [10,9,2,5,3,7,101,18] -Output: 4 - -Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. ----------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [0,1,0,3,2,3] -Output: 4 ----------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums = [7,7,7,7,7,7,7] -Output: 1 ----------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 2500 --10000 <= nums[i] <= 10000 ----------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 4 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## C# -```c# -// [1, 3, 5, 4, 3, 6, 2, 4, 5, 7, 4] # nums -// [1, 2, 3, 1, 1, 2, 1, 2, 3, 4, 1] # dp -public class Solution -{ - public int FindLengthOfLCIS(int[] nums) - { - var dp = new int[nums.Length]; - Array.Fill(dp, 1); - - for (var i = 1; i < nums.Length; i++) - { - if (nums[i] > nums[i - 1]) - { - dp[i] = dp[i - 1] + 1; - } - } - - return dp.Max(); // If you want to beat 90%, refer to Java code. - } -} -``` - -## Java -```java -class Solution { - public int findLengthOfLCIS(int[] nums) { - var result = 1; - var dp = new int[nums.length]; - Arrays.fill(dp, 1); - - for (var i = 1; i < nums.length; i++) { - if (nums[i] > nums[i - 1]) { - dp[i] = dp[i - 1] + 1; - result = Math.max(result, dp[i]); - } - } - - return result; - } -} -``` - -## Python -### Solution 1 -```python -class Solution: - def findLengthOfLCIS(self, nums: List[int]) -> int: - dp = [1] * len(nums) - - for i, num in enumerate(nums): - if i == 0: - continue - - if num > nums[i - 1]: - dp[i] = dp[i - 1] + 1 - - return max(dp) -``` - -### Solution 2 -```python -class Solution: - def findLengthOfLCIS(self, nums: List[int]) -> int: - result = 1 - current_length = 1 - - for i in range(1, len(nums)): - if nums[i] > nums[i - 1]: - current_length += 1 - - if current_length > result: - result = current_length - else: - current_length = 1 - - return result -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var findLengthOfLCIS = function (nums) { - const dp = Array(nums.length).fill(1) - - nums.forEach((num, i) => { - for (let j = i - 1; j >= 0; j--) { - if (num > nums[i - 1]) { - dp[i] = dp[i - 1] + 1 - } - } - }) - - return Math.max(...dp) // If you want to beat 90%, refer to Java code. -}; -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/684-redundant-connection.md b/en/1-1000/684-redundant-connection.md deleted file mode 100644 index 6ac56f3..0000000 --- a/en/1-1000/684-redundant-connection.md +++ /dev/null @@ -1,409 +0,0 @@ -# LeetCode 684. Redundant Connection's Solution -LeetCode link: [684. Redundant Connection](https://leetcode.com/problems/redundant-connection) - -## LeetCode problem description -In this problem, a tree is an **undirected graph** that is connected and has no cycles. - -You are given a graph that started as a tree with `n` nodes labeled from `1` to `n`, with one additional edge added. The added edge has two **different** vertices chosen from `1` to `n`, and was not an edge that already existed. The graph is represented as an array `edges` of length `n` where `edges[i] = [ai, bi]` indicates that there is an edge between nodes `ai` and `bi` in the graph. - -Return an edge that can be removed so that the resulting graph is a tree of `n` nodes. If there are multiple answers, return the answer that occurs last in the input. - -### Example 1 -![](../../images/examples/684_1.jpg) -``` -Input: edges = [[1,2],[1,3],[2,3]] -Output: [2,3] -``` - -### Example 2 -![](../../images/examples/684_2.jpg) -``` -Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]] -Output: [1,4] -``` - -### Constraints -- `n == edges.length` -- `3 <= n <= 1000` -- `edges[i].length == 2` -- `1 <= ai < bi <= edges.length` -- `ai != bi` -- There are no repeated edges. -- The given graph is connected. - -## Intuition -- In graph theory, a tree is an _undirected graph_ in which any two vertices are connected by exactly one path, or equivalently a **connected acyclic undirected graph**. Like this: -![A labeled tree with six vertices and five edges.](../../images/graph_tree_1.png) - -- When an edge is added to the graph, its two nodes are also added to the graph. -- If the two nodes are already in the graph, then they must be on the same tree. At this time, a cycle is bound to be formed. - -![](../../images/684.png) - -- We are given `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**. -- Finally, those trees can be merged into one tree if the redundant edge is removed. -- `UnionFind` algorithm is designed for grouping and searching data. - -### 'UnionFind' algorithm -- `UnionFind` algorithm typically has three methods: - - The `unite(node1, node2)` operation is used to merge two trees. - - The `find_root(node)` method is used to return the root of a node. - - The `is_same_root(node1, node2) == true` method is used to determine whether two nodes are in the same tree. - -## Approach (UnionFind algorithm) -1. Initially, each node is in its own group. -1. Iterate `edges` data and `unite(node1, node2)`. -1. As soon as `is_same_root(node1, node2) == true` (a cycle will be formed), return `[node1, node2]`. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: - self.parents = list(range(len(edges) + 1)) - - for x, y in edges: - if self.is_same_root(x, y): - return [x, y] - - self.unite(x, y) - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x # Error-prone point 1 - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) # Error-prone point 2 - - self.parents[x] = root # Error-prone point 3 - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -## Java -```java -class Solution { - private int[] parents; - - public int[] findRedundantConnection(int[][] edges) { - parents = new int[edges.length + 1]; - - for (var i = 0; i < parents.length; i++) { - parents[i] = i; - } - - for (var edge : edges) { - if (isSameRoot(edge[0], edge[1])) { - return edge; - } - - unite(edge[0], edge[1]); - } - - return null; - } - - private void unite(int x, int y) { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - private int findRoot(int x) { - var parent = parents[x]; - - if (x == parent) { - return x; - } - - var root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - private boolean isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -} -``` - -## C++ -```cpp -class Solution { -public: - vector findRedundantConnection(vector>& edges) { - for (auto i = 0; i <= edges.size(); i++) { - parents.push_back(i); - } - - for (auto& edge : edges) { - if (isSameRoot(edge[0], edge[1])) { - return edge; - } - - unite(edge[0], edge[1]); - } - - return {}; - } - -private: - vector parents; - - void unite(int x, int y) { - int root_x = findRoot(x); - int root_y = findRoot(y); - - parents[root_y] = root_x; // Error-prone point 1 - } - - int findRoot(int x) { - auto parent = parents[x]; - - if (x == parent) { - return x; - } - - auto root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -}; -``` - -## JavaScript -```javascript -let parents - -var findRedundantConnection = function(edges) { - parents = [] - for (let i = 0; i <= edges.length; i++) { - parents.push(i) - } - - for (let [x, y] of edges) { - if (isSameRoot(x, y)) { - return [x, y] - } - - unite(x, y) - } - - return isSameRoot(source, destination) -}; - -function unite(x, y) { - rootX = findRoot(x) - rootY = findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -function findRoot(x) { - const parent = parents[x] - - if (x == parent) { - return x - } - - const root = findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -function isSameRoot(x, y) { - return findRoot(x) == findRoot(y) -} -``` - -## C# -```c# -public class Solution -{ - int[] parents; - - public int[] FindRedundantConnection(int[][] edges) - { - parents = new int[edges.Length + 1]; - - for (int i = 0; i < parents.Length; i++) - parents[i] = i; - - foreach (int[] edge in edges) - { - if (isSameRoot(edge[0], edge[1])) - { - return edge; - } - - unite(edge[0], edge[1]); - } - - return null; - } - - void unite(int x, int y) - { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - int findRoot(int x) - { - int parent = parents[x]; - - if (x == parent) - return x; - - int root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) - { - return findRoot(x) == findRoot(y); - } -} -``` - -## Go -```go -var parents []int - -func findRedundantConnection(edges [][]int) []int { - parents = make([]int, len(edges) + 1) - for i := 0; i < len(parents); i++ { - parents[i] = i - } - - for _, edge := range edges { - if isSameRoot(edge[0], edge[1]) { - return edge - } - - unite(edge[0], edge[1]) - } - - return nil -} - -func unite(x, y int) { - rootX := findRoot(x) - rootY := findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -func findRoot(x int) int { - parent := parents[x]; - - if x == parent { - return x - } - - root := findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -func isSameRoot(x, y int) bool { - return findRoot(x) == findRoot(y) -} -``` - -## Ruby -```ruby -def find_redundant_connection(edges) - @parents = [] - (0..edges.size).each { |i| @parents << i } - - edges.each do |edge| - if is_same_root(edge[0], edge[1]) - return edge - end - - unite(edge[0], edge[1]) - end -end - -def unite(x, y) - root_x = find_root(x) - root_y = find_root(y) - - @parents[root_y] = root_x # Error-prone point 1 -end - -def find_root(x) - parent = @parents[x] - - if x == parent - return x - end - - root = find_root(parent) # Error-prone point 2 - - @parents[x] = root # Error-prone point 3 - - root -end - -def is_same_root(x, y) - find_root(x) == find_root(y) -end -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/685-redundant-connection-ii.md b/en/1-1000/685-redundant-connection-ii.md deleted file mode 100644 index 55867a5..0000000 --- a/en/1-1000/685-redundant-connection-ii.md +++ /dev/null @@ -1,183 +0,0 @@ -# LeetCode 685. Redundant Connection II's Solution -LeetCode link: [685. Redundant Connection II](https://leetcode.com/problems/redundant-connection-ii) - -## LeetCode problem description -In this problem, a rooted tree is a **directed** graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents. - -The given input is a directed graph that started as a rooted tree with `n` nodes (with distinct values from `1` to `n`), with one additional directed edge added. The added edge has two different vertices chosen from `1` to `n`, and was not an edge that already existed. - -The resulting graph is given as a 2D-array of `edges`. Each element of `edges` is a pair `[ui, vi]` that represents a directed edge connecting nodes `ui` and `vi`, where `ui` is a parent of child `vi`. - -Return _an edge that can be removed so that the resulting graph is a rooted tree of `n` nodes_. If there are multiple answers, return the answer that occurs last in the given 2D-array. - -### Example 1 -![](../../images/examples/685_1.jpg) -```java -Input: edges = [[1,2],[1,3],[2,3]] -Output: [2,3] -``` - -### Example 2 -![](../../images/examples/685_2.jpg) -```java -Input: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]] -Output: [4,1] -``` - -### Constraints -- `n == edges.length` -- `3 <= n <= 1000` -- `edges[i].length == 2` -- `1 <= ui, vi <= n` -- `ui != vi` - -## Intuition -- Because a cycle is formed, the directed tree is no longer a directed tree. There are two cases to consider: - 1. If there is a vertex with in-degree 2, it will form a cycle. So one of the edges needs to be removed (returned). - 2. If there is no vertex with in-degree 2, once a cycle is formed, return the edge that causes the cycle. - -- We are given `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**. -- Finally, those trees can be merged into one tree if the redundant edge is removed. -- `UnionFind` algorithm is designed for grouping and searching data. - -### 'UnionFind' algorithm -- `UnionFind` algorithm typically has three methods: - - The `unite(node1, node2)` operation is used to merge two trees. - - The `find_root(node)` method is used to return the root of a node. - - The `is_same_root(node1, node2)` method is used to determine whether two nodes are in the same tree. - -## Approach -1. Iterate `edges` data to look for the `two_conflict_edges` (the two edges caused a vertex with in-degree 2). -1. Initially, each node is in its own group. -1. Iterate `edges` data and `unite(node1, node2)`. -1. If there is no vertex with in-degree 2, as soon as `is_same_root(node1, node2) == true` (a cycle will be formed), return `[node1, node2]`. -1. If there is a vertex with in-degree 2, we need to determine which edge in `two_conflict_edges` should be returned. -See if the graph can form a cycle by not adding the second edge to the graph. If so, return the first edge. Otherwise, return the second edge. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def findRedundantDirectedConnection(self, edges: List[List[int]]) -> List[int]: - self.parents = list(range(len(edges) + 1)) - - two_conflict_edges_ = self.two_conflict_edges(edges) - - if not two_conflict_edges_: - for x, y in edges: - if self.is_same_root(x, y): - return [x, y] - - self.unite(x, y) - - raise Exception('No suitable edge was returned!') - - for x, y in edges: - if [x, y] == two_conflict_edges_[1]: - continue - - if self.is_same_root(x, y): - return two_conflict_edges_[0] - - self.unite(x, y) - - return two_conflict_edges_[1] - - def two_conflict_edges(self, edges): - pointed_node_to_source_node = {} - - for source_node, pointed_node in edges: - if pointed_node in pointed_node_to_source_node: - return [ - [pointed_node_to_source_node[pointed_node], pointed_node], - [source_node, pointed_node], - ] - - pointed_node_to_source_node[pointed_node] = source_node - - return [] - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) - - self.parents[x] = root - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Python -```python -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/695-max-area-of-island.md b/en/1-1000/695-max-area-of-island.md deleted file mode 100644 index 2893413..0000000 --- a/en/1-1000/695-max-area-of-island.md +++ /dev/null @@ -1,419 +0,0 @@ -# 695. Max Area of Island (Solution 1: 'Depth-First Search' by Recursion) -LeetCode link: [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/) - -# LeetCode problem description -You are given an `m x n` binary matrix `grid`. An island is a group of `1`'s (representing land) connected **4-directionally** (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. - -The `area` of an island is the number of cells with a value `1` in the island. - -Return _the maximum area of an island_ in `grid`. If there is no island, return `0`. - -## Example 1 -![](../../images/examples/695_1.jpg) -``` -Input: grid = [ - [0,0,1,0,0,0,0,1,0,0,0,0,0], - [0,0,0,0,0,0,0,1,1,1,0,0,0], - [0,1,1,0,1,0,0,0,0,0,0,0,0], - [0,1,0,0,1,1,0,0,1,0,1,0,0], - [0,1,0,0,1,1,0,0,1,1,1,0,0], - [0,0,0,0,0,0,0,0,0,0,1,0,0], - [0,0,0,0,0,0,0,1,1,1,0,0,0], - [0,0,0,0,0,0,0,1,1,0,0,0,0] -] -Output: 6 -Explanation: The answer is not 11, because the island must be connected 4-directionally. -``` - -## Example 2 -``` -Input: grid = [[0,0,0,0,0,0,0,0]] -Output: 0 -``` - -## Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 50` -- `grid[i][j]` is either `0` or `1`. - -## Intuition -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Return _the maximum area of an island_ is to return the vertex count of the largest **connected component**. - -## Approach -1. Find the first land. -2. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * When we traverse each `connected components` (island), we can: - * Mark each found land as `8` which represents `visited` (or `included` in `area`). Visited lands don't need to be visited again. - * **count** the lands of the island. -3. After all lands on an island have been visited, look for the next non-visited land. -4. Repeat the above two steps until all the lands have been `visited`. -5. At last, return the `max_area`. - -## Solution 1: 'Depth-First Search' by Recursion -![](../../images/binary_tree_DFS_1.png) - -From this sample code bellow, you can see that starting from a vertex, through recursive calls, it goes up until it can't go any further, turns right, and continues up. The priority order of directions is `up, right, down, left`. -```java -depth_first_search(i - 1, j); // up -depth_first_search(i, j + 1); // right -depth_first_search(i + 1, j); // down -depth_first_search(i, j - 1); // left -``` - -## Solution 2: 'Depth-First Search' by Iteration -Similar problem is `200. Number of Islands`, please click [Depth-First Search by Iteration Solution](200-number-of-islands-2.md) to view. - -## Solution 3: Breadth-First Search -Similar problem is `200. Number of Islands`, please click [Breadth-First Search Solution](200-number-of-islands-3.md) to view. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -# Python -```python -class Solution: - def __init__(self): - self.max_area = 0 - self.area = 0 - self.grid = None - - def maxAreaOfIsland(self, grid: List[List[int]]) -> int: - self.grid = grid - - for i in range(len(grid)): - for j in range(len(grid[0])): - if grid[i][j] == 1: - self.area = 0 - self.depth_first_search(i, j) - self.max_area = max(self.max_area, self.area) - - return self.max_area - - def depth_first_search(self, i, j): - if i < 0 or j < 0 or i >= len(self.grid) or j >= len(self.grid[0]): - return - - if self.grid[i][j] != 1: - return - - self.grid[i][j] = 8 - self.area += 1 - - for m, n in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0), - ]: - self.depth_first_search(i + m, j + n) -``` - -# Java -```java -class Solution { - int[][] grid; - int maxArea = 0; - int area = 0; - - public int maxAreaOfIsland(int[][] grid) { - this.grid = grid; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == 1) { - area = 0; - depthFirstSearch(i, j); - maxArea = Math.max(maxArea, area); - } - } - } - - return maxArea; - } - - void depthFirstSearch(int i, int j) { - if (i < 0 || i >= grid.length) { - return; - } - - if (j < 0 || j >= grid[0].length) { - return; - } - - if (grid[i][j] != 1) { - return; - } - - grid[i][j] = 8; - area++; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# C++ -```cpp -class Solution { -public: - int maxAreaOfIsland(vector>& grid) { - grid_ = grid; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == 1) { - area_ = 0; - depth_first_search(i, j); - max_area_ = max(max_area_, area_); - } - } - } - - return max_area_; - } - -private: - vector> grid_; - int max_area_ = 0; - int area_ = 0; - - void depth_first_search(int i, int j) { - if ( - i < 0 || i >= grid_.size() || - j < 0 || j >= grid_[0].size() || - grid_[i][j] != 1 - ) { - return; - } - - grid_[i][j] = 8; - area_++; - - depth_first_search(i - 1, j); - depth_first_search(i, j + 1); - depth_first_search(i + 1, j); - depth_first_search(i, j - 1); - } -}; -``` - -# JavaScript -```JavaScript -let grid -let maxArea = 0 -let area - -var maxAreaOfIsland = function (grid_) { - grid = grid_ - maxArea = 0 - - grid.forEach((row, i) => { - row.forEach((value, j) => { - if (value === 1) { - area = 0 - depthFirstSearch(i, j) - maxArea = Math.max(maxArea, area) - } - }) - }) - - return maxArea -}; - - -function depthFirstSearch(i, j) { - if (i < 0 || i >= grid.length) { - return - } - - if (j < 0 || j >= grid[0].length) { - return - } - - if (grid[i][j] != 1) { - return - } - - grid[i][j] = 8 - area++ - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# C# -```c# -public class Solution -{ - int[][] grid; - int maxArea = 0; - int area = 0; - - public int MaxAreaOfIsland(int[][] grid) - { - this.grid = grid; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == 1) - { - area = 0; - depthFirstSearch(i, j); - maxArea = Math.Max(maxArea, area); - } - } - } - - return maxArea; - } - - void depthFirstSearch(int i, int j) - { - if (i < 0 || i >= grid.Length) - return; - - if (j < 0 || j >= grid[0].Length) - return; - - if (grid[i][j] != 1) - return; - - grid[i][j] = 8; - area++; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# Go -```go -var ( - grid [][]int - maxArea int - area int -) - -func maxAreaOfIsland(grid_ [][]int) int { - grid = grid_ - maxArea = 0 - - for i, row := range grid { - for j, value := range row { - if value == 1 { - area = 0 - depthFirstSearch(i, j) - maxArea = max(maxArea, area) - } - } - } - - return maxArea -} - -func depthFirstSearch(i int, j int) { - if i < 0 || i >= len(grid) { - return - } - - if j < 0 || j >= len(grid[0]) { - return - } - - if grid[i][j] != 1 { - return - } - - grid[i][j] = 8 - area++ - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# Ruby -```Ruby -def max_area_of_island(grid) - @grid = grid - @max_area = 0 - @area = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == 1 - @area = 0 - depth_first_search(i, j) - @max_area = [@max_area, @area].max - end - end - end - - @max_area -end - -def depth_first_search(i, j) - return if i < 0 || i >= @grid.size - - return if j < 0 || j >= @grid[0].size - - return if @grid[i][j] != 1 - - @grid[i][j] = 8 - @area += 1 - - depth_first_search(i - 1, j) - depth_first_search(i, j + 1) - depth_first_search(i + 1, j) - depth_first_search(i, j - 1) -end -``` - -# C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/704-binary-search.md b/en/1-1000/704-binary-search.md deleted file mode 100644 index f40fd3f..0000000 --- a/en/1-1000/704-binary-search.md +++ /dev/null @@ -1,245 +0,0 @@ -# 704. Binary Search - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [704. Binary Search - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/704-binary-search) for a better experience! - -LeetCode link: [704. Binary Search](https://leetcode.com/problems/binary-search), difficulty: **Easy**. - -## LeetCode description of "704. Binary Search" - -Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its `index`. Otherwise, return `-1`. - -You must write an algorithm with `O(log n)` runtime complexity. - -### [Example 1] - -**Input**: `nums = [-1,0,3,5,9,12], target = 9` - -**Output**: `4` - -**Explanation**: `9 exists in `nums` and its index is 4` - -### [Example 2] - -**Input**: `nums = [-1,0,3,5,9,12], target = 2` - -**Output**: `-1` - -**Explanation**: `2 does not exist in `nums` so return -1` - -### [Constraints] - -- `1 <= nums.length <= 10000` -- `104 < nums[i], target < 10000` -- All the integers in `nums` are **unique**. -- `nums` is sorted in ascending order. - -## Intuition - -Because it is an already sorted array, by using the middle value for comparison, half of the numbers can be eliminated each time. - -## Step by Step Solutions - -The fastest and easiest way is to use the three indices `left`, `right`, and `middle`. -If `nums[middle] > target`, then `right = middle - 1`, otherwise, `left = middle + 1`. - -## Complexity - -- Time complexity: `O(log N)`. -- Space complexity: `O(1)`. - -## Java - -```java -class Solution { - public int search(int[] nums, int target) { - var left = 0; - var right = nums.length - 1; - - while (left <= right) { - var middle = (left + right) / 2; - - if (nums[middle] == target) { - return middle; - } - - if (nums[middle] > target) { - right = middle - 1; - } else { - left = middle + 1; - } - } - - return -1; - } -} -``` - -## Python - -```python -class Solution: - def search(self, nums: List[int], target: int) -> int: - left = 0 - right = len(nums) - 1 - - while left <= right: - middle = (left + right) // 2 - - if nums[middle] == target: - return middle - - if nums[middle] > target: - right = middle - 1 - else: - left = middle + 1 - - return -1 -``` - -## C++ - -```cpp -class Solution { -public: - int search(vector& nums, int target) { - auto left = 0; - int right = nums.size() - 1; // Should not use 'auto' here because 'auto' will make this variable become `unsigned long` which has no `-1`. - - while (left <= right) { - auto middle = (left + right) / 2; - - if (nums[middle] == target) { - return middle; - } - - if (nums[middle] > target) { - right = middle - 1; - } else { - left = middle + 1; - } - } - - return -1; - } -}; -``` - -## JavaScript - -```javascript -var search = function (nums, target) { - let left = 0 - let right = nums.length - 1 - - while (left <= right) { - const middle = Math.floor((left + right) / 2) - - if (nums[middle] == target) { - return middle - } - - if (nums[middle] > target) { - right = middle - 1 - } else { - left = middle + 1 - } - } - - return -1 -}; -``` - -## C# - -```csharp -public class Solution -{ - public int Search(int[] nums, int target) - { - int left = 0; - int right = nums.Length - 1; - - while (left <= right) - { - int middle = (left + right) / 2; - - if (nums[middle] == target) - { - return middle; - } - - if (nums[middle] > target) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return -1; - } -} -``` - -## Go - -```go -func search(nums []int, target int) int { - left := 0 - right := len(nums) - 1 - - for left <= right { - middle := (left + right) / 2 - - if nums[middle] == target { - return middle - } - - if nums[middle] > target { - right = middle - 1 - } else { - left = middle + 1 - } - } - - return -1 -} -``` - -## Ruby - -```ruby -def search(nums, target) - left = 0 - right = nums.size - 1 - - while left <= right - middle = (left + right) / 2 - - return middle if nums[middle] == target - - if nums[middle] > target - right = middle - 1 - else - left = middle + 1 - end - end - - -1 -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [704. Binary Search - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/704-binary-search). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/707-design-linked-list.md b/en/1-1000/707-design-linked-list.md deleted file mode 100644 index 96315ed..0000000 --- a/en/1-1000/707-design-linked-list.md +++ /dev/null @@ -1,641 +0,0 @@ -# 707. Design Linked List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [707. Design Linked List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/707-design-linked-list) for a better experience! - -LeetCode link: [707. Design Linked List](https://leetcode.com/problems/design-linked-list), difficulty: **Medium**. - -## LeetCode description of "707. Design Linked List" - -Design your implementation of the linked list. You can choose to use a singly or doubly linked list. - -A node in a singly linked list should have two attributes: `val` and `next`. `val` is the value of the current node, and `next` is a pointer/reference to the next node. - -If you want to use the doubly linked list, you will need one more attribute `prev` to indicate the previous node in the linked list. Assume all nodes in the linked list are **0-indexed**. - - -Implement the `MyLinkedList` class: - -- `MyLinkedList()` Initializes the `MyLinkedList` object. -- `int get(int index)` Get the value of the *indexth* node in the linked list. If the index is invalid, return `-1`. -- `void addAtHead(int val)` Add a node of value `val` before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. -- `void addAtTail(int val)` Append a node of value `val` as the last element of the linked list. -- `void addAtIndex(int index, int val)` Add a node of value `val` before the *indexth* node in the linked list. If `index` equals the length of the linked list, the node will be appended to the end of the linked list. If `index` is greater than the length, the node will **not be inserted**. -- `void deleteAtIndex(int index)` Delete the *indexth* node in the linked list, if the index is valid. - -### [Example 1] - -**Input**: `["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"] [[], [1], [3], [1, 2], [1], [1], [1]]` - -**Output**: `[null, null, null, null, 2, null, 3]` - -**Explanation**: - -

MyLinkedList myLinkedList = new MyLinkedList();
-myLinkedList.addAtHead(1);
-myLinkedList.addAtTail(3);
-myLinkedList.addAtIndex(1, 2); // linked list becomes 1->2->3
-myLinkedList.get(1); // return 2
-myLinkedList.deleteAtIndex(1); // now the linked list is 1->3
-myLinkedList.get(1); // return 3

- - -### [Constraints] - -- `0 <= index, val <= 1000` -- Please do not use the built-in LinkedList library. -- At most `2000` calls will be made to `get`, `addAtHead`, `addAtTail`, `addAtIndex` and `deleteAtIndex`. - -## Intuition - -Before solving this problem, it is recommended to solve the simple problem [19. Remove Nth Node From End of List](19-remove-nth-node-from-end-of-list.md) first. - -This question can comprehensively test the candidate's mastery of linked lists. The following points need to be paid attention to: - -1. It is best to use a `dummyHead` node as the entry of the linked list. -2. It is best to use a new `ListNode` class, so that `dummyHead` does not need to be mixed with `val` and `next`. -3. Implement the easy methods first, in the order of `addAtHead`, `addAtTail`, `addAtIndex`, `deleteAtIndex`, `get`. - -## Complexity - -- Time complexity: `O(N * N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class ListNode { - int val; - ListNode next; - - ListNode(int val) { - this.val = val; - } -} - -class MyLinkedList { - private ListNode dummyHead = new ListNode(0); - - public MyLinkedList() {} - - public int get(int index) { - var node = dummyHead.next; - var i = 0; - - while (node != null && i < index) { - node = node.next; - i += 1; - } - - if (i == index && node != null) { - return node.val; - } - - return -1; - } - - public void addAtHead(int val) { - var node = new ListNode(val); - node.next = dummyHead.next; - dummyHead.next = node; - } - - public void addAtTail(int val) { - var node = dummyHead; - - while (node.next != null) { - node = node.next; - } - - node.next = new ListNode(val); - } - - public void addAtIndex(int index, int val) { - var node = dummyHead; - var i = 0; - - while (node.next != null && i < index) { - node = node.next; - i += 1; - } - - if (i == index) { - var newNode = new ListNode(val); - newNode.next = node.next; - node.next = newNode; - } - } - - public void deleteAtIndex(int index) { - var node = dummyHead; - var i = 0; - - while (node.next != null && i < index) { - node = node.next; - i += 1; - } - - if (i == index && node.next != null) { - node.next = node.next.next; - } - } -} -``` - -## Python - -```python -class ListNode: - def __init__(self, val=None): - self.val = val - self.next = None - - -class MyLinkedList: - def __init__(self): - self.dummy_head = ListNode() - - def get(self, index: int) -> int: - node = self.dummy_head.next - i = 0 - - while node and i < index: - node = node.next - i += 1 - - if i == index and node: - return node.val - - return -1 - - def addAtHead(self, val: int) -> None: - node = ListNode(val) - node.next = self.dummy_head.next - self.dummy_head.next = node - - def addAtTail(self, val: int) -> None: - node = self.dummy_head - - while node.next: - node = node.next - - node.next = ListNode(val) - - def addAtIndex(self, index: int, val: int) -> None: - node = self.dummy_head - i = 0 - - while node.next and i < index: - node = node.next - i += 1 - - if i == index: - new_node = ListNode(val) - new_node.next = node.next - node.next = new_node - - def deleteAtIndex(self, index: int) -> None: - node = self.dummy_head - i = 0 - - while node.next and i < index: - node = node.next - i += 1 - - if i == index and node.next: - node.next = node.next.next -``` - -## JavaScript - -```javascript -class ListNode { - constructor(val) { - this.val = val - this.next = null - } -} - -var MyLinkedList = function () { - this.dummyHead = new ListNode(0) -}; - -MyLinkedList.prototype.get = function (index) { - let node = this.dummyHead.next - let i = 0 - - while (node != null && i < index) { - node = node.next - i += 1 - } - - if (i == index && node != null) { - return node.val - } - - return -1 -}; - -MyLinkedList.prototype.addAtHead = function (val) { - const node = new ListNode(val) - node.next = this.dummyHead.next - this.dummyHead.next = node -}; - -MyLinkedList.prototype.addAtTail = function (val) { - let node = this.dummyHead - - while (node.next != null) { - node = node.next - } - - node.next = new ListNode(val) -}; - -MyLinkedList.prototype.addAtIndex = function (index, val) { - let node = this.dummyHead - let i = 0 - - while (node.next != null && i < index) { - node = node.next - i += 1 - } - - if (i == index) { - const newNode = new ListNode(val); - newNode.next = node.next; - node.next = newNode; - } -}; - -MyLinkedList.prototype.deleteAtIndex = function (index) { - let node = this.dummyHead - let i = 0 - - while (node.next != null && i < index) { - node = node.next - i += 1 - } - - if (i == index && node.next != null) { - node.next = node.next.next - } -}; -``` - -## C# - -```csharp -public class ListNode -{ - public int val; - public ListNode next; - - public ListNode(int val) - { - this.val = val; - } -} - -public class MyLinkedList -{ - ListNode dummyHead = new ListNode(0); - - public MyLinkedList() {} - - public int Get(int index) - { - var node = dummyHead.next; - int i = 0; - - while (node != null && i < index) - { - node = node.next; - i += 1; - } - - if (i == index && node != null) - return node.val; - - return -1; - } - - public void AddAtHead(int val) - { - var node = new ListNode(val); - node.next = dummyHead.next; - dummyHead.next = node; - } - - public void AddAtTail(int val) - { - var node = dummyHead; - - while (node.next != null) - node = node.next; - - node.next = new ListNode(val); - } - - public void AddAtIndex(int index, int val) - { - var node = dummyHead; - int i = 0; - - while (node.next != null && i < index) - { - node = node.next; - i += 1; - } - - if (i == index) { - var newNode = new ListNode(val); - newNode.next = node.next; - node.next = newNode; - } - } - - public void DeleteAtIndex(int index) - { - var node = dummyHead; - int i = 0; - - while (node.next != null && i < index) - { - node = node.next; - i += 1; - } - - if (i == index && node.next != null) - node.next = node.next.next; - } -} -``` - -## Go - -```go -// ListNode represents a node in the singly-linked list -// type ListNode struct { -// Val int -// Next *ListNode -// } - -// MyLinkedList implements linked list operations using a dummy head node -type MyLinkedList struct { - dummyHead *ListNode -} - -// Constructor initializes a new linked list -func Constructor() MyLinkedList { - return MyLinkedList{ - dummyHead: &ListNode{}, // Initialize dummy head with zero value - } -} - -// Get retrieves the value at specified index, returns -1 for invalid indices -func (ll *MyLinkedList) Get(index int) int { - current := ll.dummyHead.Next - count := 0 - - // Traverse until reaching desired index or end of list - for current != nil && count < index { - current = current.Next - count++ - } - - // Validate index and return value if found - if current != nil && count == index { - return current.Val - } - return -1 -} - -// AddAtHead inserts new node at beginning of the list -func (ll *MyLinkedList) AddAtHead(val int) { - newNode := &ListNode{Val: val} - newNode.Next = ll.dummyHead.Next - ll.dummyHead.Next = newNode -} - -// AddAtTail appends new node at end of the list -func (ll *MyLinkedList) AddAtTail(val int) { - current := ll.dummyHead - // Traverse to last node - for current.Next != nil { - current = current.Next - } - current.Next = &ListNode{Val: val} -} - -// AddAtIndex inserts node at specified position if valid -func (ll *MyLinkedList) AddAtIndex(index int, val int) { - prev := ll.dummyHead - count := 0 - - // Find insertion point - for prev.Next != nil && count < index { - prev = prev.Next - count++ - } - - // Only insert if index matches traversal count - if count == index { - newNode := &ListNode{Val: val} - newNode.Next = prev.Next - prev.Next = newNode - } -} - -// DeleteAtIndex removes node at specified position if valid -func (ll *MyLinkedList) DeleteAtIndex(index int) { - prev := ll.dummyHead - count := 0 - - // Find node preceding the deletion target - for prev.Next != nil && count < index { - prev = prev.Next - count++ - } - - // Perform deletion if index is valid and node exists - if prev.Next != nil && count == index { - prev.Next = prev.Next.Next - } -} -``` - -## C++ - -```cpp -class MyLinkedList { -private: - struct ListNode { - int val; - ListNode* next; - ListNode(int x) : val(x), next(nullptr) {} - }; - - ListNode* dummy_head_; - -public: - MyLinkedList() { - dummy_head_ = new ListNode(0); - } - - int get(int index) { - auto node = dummy_head_->next; - auto i = 0; - - while (node && i < index) { - node = node->next; - i++; - } - - return (i == index && node) ? node->val : -1; - } - - void addAtHead(int val) { - auto node = new ListNode(val); - node->next = dummy_head_->next; - dummy_head_->next = node; - } - - void addAtTail(int val) { - auto node = dummy_head_; - while (node->next) { - node = node->next; - } - node->next = new ListNode(val); - } - - void addAtIndex(int index, int val) { - auto node = dummy_head_; - auto i = 0; - - while (node->next && i < index) { - node = node->next; - i++; - } - - if (i == index) { - auto new_node = new ListNode(val); - new_node->next = node->next; - node->next = new_node; - } - } - - void deleteAtIndex(int index) { - auto node = dummy_head_; - auto i = 0; - - while (node->next && i < index) { - node = node->next; - i++; - } - - if (i == index && node->next) { - auto to_delete = node->next; - node->next = node->next->next; - delete to_delete; - } - } -}; - -``` - -## Ruby - -```ruby -# ListNode class with val and next_node (since 'next' is reserved in some languages) -class ListNode - attr_accessor :val, :next_node - - def initialize(val = nil) - @val = val - @next_node = nil - end -end - -# MyLinkedList implementation with dummy head -class MyLinkedList - def initialize - @dummy_head = ListNode.new # Dummy head node - end - - # Get value at index, return -1 if invalid - def get(index) - current = @dummy_head.next_node - count = 0 - - while current && count < index - current = current.next_node - count += 1 - end - - current && count == index ? current.val : -1 - end - - # Add node at head - def add_at_head(val) - new_node = ListNode.new(val) - new_node.next_node = @dummy_head.next_node - @dummy_head.next_node = new_node - end - - # Add node at tail - def add_at_tail(val) - current = @dummy_head - - while current.next_node - current = current.next_node - end - - current.next_node = ListNode.new(val) - end - - # Add node at index if valid - def add_at_index(index, val) - prev = @dummy_head - count = 0 - - while prev.next_node && count < index - prev = prev.next_node - count += 1 - end - - if count == index - new_node = ListNode.new(val) - new_node.next_node = prev.next_node - prev.next_node = new_node - end - end - - # Delete node at index if valid - def delete_at_index(index) - prev = @dummy_head - count = 0 - - while prev.next_node && count < index - prev = prev.next_node - count += 1 - end - - if prev.next_node && count == index - prev.next_node = prev.next_node.next_node - end - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [707. Design Linked List - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/707-design-linked-list). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md b/en/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md deleted file mode 100644 index 8f6c38f..0000000 --- a/en/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md +++ /dev/null @@ -1,132 +0,0 @@ -# 714. Best Time to Buy and Sell Stock with Transaction Fee -LeetCode link: [714. Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day, and an integer `fee` representing a transaction fee. - -Find the **maximum profit** you can achieve. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. - -**Note:** - -* You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). -* The transaction fee is only charged once for each stock purchase and sale. - -``` ------------------------------------------------------------------- -[Example 1] - -Input: prices = [1,3,2,8,4,9], fee = 2 -Output: 8 - -Explanation: The maximum profit can be achieved by: -- Buying at prices[0] = 1 -- Selling at prices[3] = 8 -- Buying at prices[4] = 4 -- Selling at prices[5] = 9 -The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8. ------------------------------------------------------------------- -[Example 2] - -Input: prices = [1,3,7,5,10,3], fee = 3 -Output: 6 ------------------------------------------------------------------- -[Constraints] - -1 <= prices.length <= 5 * 10000 -1 <= prices[i] < 5 * 10000 -0 <= fee < 5 * 10000 ------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int], fee: int) -> int: - # states: - # 0: hold stock - # 1) keep holding - # 2) today just bought - # 1: no stock - # 1) keep no stock - # 2) today just sold - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], dc[1] - price) - dp[1] = max(dc[1], dc[0] + price - fee) - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices, fee) { - const dp = [-prices[0], 0] - - for (let i = 1; i < prices.length; i++) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], dc[1] - prices[i]) - dp[1] = Math.max(dc[1], dc[0] + prices[i] - fee) - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int, fee int) int { - dp := []int{-prices[0], 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], dc[1] - prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i] - fee) - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/718-maximum-length-of-repeated-subarray.md b/en/1-1000/718-maximum-length-of-repeated-subarray.md deleted file mode 100644 index a079ccb..0000000 --- a/en/1-1000/718-maximum-length-of-repeated-subarray.md +++ /dev/null @@ -1,148 +0,0 @@ -# 718. Maximum Length of Repeated Subarray -LeetCode link: [718. Maximum Length of Repeated Subarray](https://leetcode.com/problems/maximum-length-of-repeated-subarray/) - -## LeetCode problem description -Given two integer arrays `nums1` and `nums2`, return the **maximum length of a subarray** that appears in **both** arrays. - -``` ------------------------------------------------------------------------- -[Example 1] - -Input: nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] -Output: 3 - -Explanation: The repeated subarray with maximum length is [3,2,1]. ------------------------------------------------------------------------- -[Example 2] - -Input: nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0] -Output: 5 - -Explanation: The repeated subarray with maximum length is [0,0,0,0,0]. ------------------------------------------------------------------------- -[Constraints] - -1 <= nums1.length, nums2.length <= 1000 -0 <= nums1[i], nums2[i] <= 100 ------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 4 to 7 languages are given. - -**Do not use a rolling array** as `dp` because that is more difficult to write and understand. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Java -```java -class Solution { - public int findLength(int[] nums1, int[] nums2) { - var maxLength = 0; - var dp = new int[nums1.length + 1][nums2.length + 1]; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - maxLength = Math.max(dp[i][j], maxLength); - } - } - } - - return maxLength; - } -} -``` - -## C# -```c# -public class Solution -{ - public int FindLength(int[] nums1, int[] nums2) - { - int maxLength = 0; - var dp = new int[nums1.Length + 1, nums2.Length + 1]; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (nums1[i - 1] == nums2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1] + 1; - maxLength = Math.Max(dp[i, j], maxLength); - } - } - } - - return maxLength; - } -} -``` - -## Python -```python -class Solution: - def findLength(self, nums1: List[int], nums2: List[int]) -> int: - max_length = 0 - dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if nums1[i - 1] == nums2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - max_length = max(dp[i][j], max_length) - - return max_length -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var findLength = function (nums1, nums2) { - let maxLength = 0 - const dp = Array(nums1.length + 1).fill().map( - () => Array(nums2.length + 1).fill(0) - ) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - maxLength = Math.max(dp[i][j], maxLength) - } - } - } - - return maxLength -}; -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/72-edit-distance.md b/en/1-1000/72-edit-distance.md deleted file mode 100644 index d62f040..0000000 --- a/en/1-1000/72-edit-distance.md +++ /dev/null @@ -1,382 +0,0 @@ -# 72. Edit Distance - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [72. Edit Distance - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/72-edit-distance) for a better experience! - -LeetCode link: [72. Edit Distance](https://leetcode.com/problems/edit-distance), difficulty: **Medium**. - -## LeetCode description of "72. Edit Distance" - -Given two strings `word1` and `word2`, return the **minimum** number of operations required to convert `word1` to `word2`. - -You have the following three operations permitted on a word: - -- Insert a character -- Delete a character -- Replace a character - -### [Example 1] - -**Input**: `word1 = "horse", word2 = "ros"` - -**Output**: `3` - -**Explanation**: - -

horse -> rorse (replace 'h' with 'r')
-rorse -> rose (remove 'r')
-rose -> ros (remove 'e')

- - -### [Example 2] - -**Input**: `word1 = "intention", word2 = "execution"` - -**Output**: `5` - -**Explanation**: - -

intention -> inention (remove 't')
-inention -> enention (replace 'i' with 'e')
-enention -> exention (replace 'n' with 'x')
-exention -> exection (replace 'n' with 'c')
-exection -> execution (insert 'u')

- - -### [Constraints] - -1. `0 <= word1.length, word2.length <= 500` -2. `word1` and `word2` consist of lowercase English letters. - -## Intuition - -It is a question of comparing two strings. After doing similar questions many times, we will develop an intuition to use Dynamic Programming with *two-dimensional* arrays. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Pattern of "Subsequence Problems" - -- Since there are two swappable arrays (or strings) to compare, we can use **two-dimensional** arrays as `dp`. -- The traversal order of `dp` array is from top to bottom, then from left to right. - -## Step by Step Solutions - -1. Determine the **meaning** of each value of the array `dp`. - - `dp[i][j]` represents the **minimum** number of operations required to convert `word1`'s first `i` letters to `word2`'s first `j` letters. - - `dp[i][j]` is an integer. -2. Initialize the value of the array `dp`. - - Use an example: - - ``` - After initialization, the 'dp' array would be: - # r o s - # 0 1 2 3 # dp[0] - # h 1 0 0 0 - # o 2 0 0 0 - # r 3 0 0 0 - # s 4 0 0 0 - # e 5 0 0 0 - ``` - - `dp[i][0] = i`, because `dp[i][0]` represents the empty string, and the number of operations is just the number of chars to be deleted. - - `dp[0][j] = j`, the reason is the same as the previous line, just viewed from the opposite angle: convert `word2` to `word1`. - -3. Fill in the `dp` grid data **in order** according to an example. - - ``` - 1. Convert `h` to `ros`. - # r o s - # 0 1 2 3 - # h 1 1 2 3 # dp[1] - ``` - ``` - 2. Convert `ho` to `ros`. - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - ``` - ``` - 3. Convert `hor` to `ros`. - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - # r 3 2 2 2 - ``` - ``` - 4. Convert `hors` to `ros`. - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - # r 3 2 2 2 - # s 4 3 3 2 - ``` - ``` - 5. Convert `horse` to `ros`. - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - # r 3 2 2 2 - # s 4 3 3 2 - # e 5 4 4 3 # dp[5] - ``` -4. Based on the `dp` grid data, derive the **recursive formula**. - - ```python - if word1[i - 1] == word2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min( - dp[i - 1][j - 1], - dp[i - 1][j], - dp[i][j - 1], - ) + 1 - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(N * M)`. -- Space complexity: `O(N * M)`. - -## Java - -```java -class Solution { - public int minDistance(String word1, String word2) { - var dp = new int[word1.length() + 1][word2.length() + 1]; - for (var i = 0; i < dp.length; i++) { - dp[i][0] = i; - } - for (var j = 0; j < dp[0].length; j++) { - dp[0][j] = j; - } - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (word1.charAt(i - 1) == word2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1; - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public int MinDistance(string word1, string word2) - { - var dp = new int[word1.Length + 1, word2.Length + 1]; - - for (var i = 0; i < dp.GetLength(0); i++) - dp[i, 0] = i; - - for (var j = 0; j < dp.GetLength(1); j++) - dp[0, j] = j; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (word1[i - 1] == word2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1]; - } - else - { - dp[i, j] = Math.Min(dp[i - 1, j - 1], Math.Min(dp[i - 1, j], dp[i, j - 1])) + 1; - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Python - -```python -class Solution: - def minDistance(self, word1: str, word2: str) -> int: - dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)] - for i in range(len(dp)): - dp[i][0] = i - for j in range(len(dp[0])): - dp[0][j] = j - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if word1[i - 1] == word2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 - - return dp[-1][-1] -``` - -## C++ - -```cpp -class Solution { -public: - int minDistance(string word1, string word2) { - vector> dp(word1.size() + 1, vector(word2.size() + 1)); - for (auto i = 0; i < dp.size(); i++) { - dp[i][0] = i; - } - for (auto j = 0; j < dp[0].size(); j++) { - dp[0][j] = j; - } - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1; - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript - -```javascript -var minDistance = function (word1, word2) { - const dp = Array(word1.length + 1).fill().map( - () => Array(word2.length + 1).fill(0) - ) - dp.forEach((_, i) => { dp[i][0] = i }) - dp[0].forEach((_, j) => { dp[0][j] = j }) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go - -```go -func minDistance(word1 string, word2 string) int { - dp := make([][]int, len(word1) + 1) - for i := range dp { - dp[i] = make([]int, len(word2) + 1) - dp[i][0] = i - } - for j := range dp[0] { - dp[0][j] = j - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if word1[i - 1] == word2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby - -```ruby -def min_distance(word1, word2) - dp = Array.new(word1.size + 1) do - Array.new(word2.size + 1, 0) - end - dp.each_with_index do |_, i| - dp[i][0] = i - end - dp[0].each_with_index do |_, j| - dp[0][j] = j - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if word1[i - 1] == word2[j - 1] - dp[i - 1][j - 1] - else - [ dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1] ].min + 1 - end - end - end - - dp[-1][-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [72. Edit Distance - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/72-edit-distance). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/739-daily-temperatures.md b/en/1-1000/739-daily-temperatures.md deleted file mode 100644 index 511cdc7..0000000 --- a/en/1-1000/739-daily-temperatures.md +++ /dev/null @@ -1,217 +0,0 @@ -# 739. Daily Temperatures -LeetCode link: [739. Daily Temperatures](https://leetcode.com/problems/daily-temperatures/) - -## LeetCode problem description -Given an array of integers `temperatures` represents the daily temperatures, return an array `answer` such that `answer[i]` is the number of days you have to wait after the `i-th` day to get a warmer temperature. If there is no future day for which this is possible, keep `answer[i] == 0` instead. - -``` ------------------------------------------------------------------------- -[Example 1] - -Input: temperatures = [73,74,75,71,69,72,76,73] -Output: [1,1,4,2,1,1,0,0] ------------------------------------------------------------------------- -[Example 2] - -Input: temperatures = [30,40,50,60] -Output: [1,1,1,0] ------------------------------------------------------------------------- -[Example 3] - -Input: temperatures = [30,60,90] -Output: [1,1,0] ------------------------------------------------------------------------- -[Constraints] - -1 <= temperatures.length <= 100000 -30 <= temperatures[i] <= 100 ------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Java -```java -class Solution { - public int[] dailyTemperatures(int[] temperatures) { - var results = new int[temperatures.length]; - var indexStack = new Stack(); - - for (var i = 0; i < temperatures.length; i++) { - while (!indexStack.empty() && temperatures[indexStack.peek()] < temperatures[i]) { - var index = indexStack.pop(); - results[index] = i - index; - } - - indexStack.push(i); - } - - return results; - } -} -``` - -## Python -```python -class Solution: - def dailyTemperatures(self, temperatures: List[int]) -> List[int]: - results = [0] * len(temperatures) - index_stack = [] - - for i, temperature in enumerate(temperatures): - while index_stack and temperature > temperatures[index_stack[-1]]: - index = index_stack.pop() - results[index] = i - index - - index_stack.append(i) - - return results -``` - -## C++ -```cpp -class Solution { -public: - vector dailyTemperatures(vector& temperatures) { - vector results(temperatures.size()); - stack index_stack; - - for (auto i = 0; i < temperatures.size(); i++) { - while (!index_stack.empty() && temperatures[i] > temperatures[index_stack.top()]) { - results[index_stack.top()] = i - index_stack.top(); - index_stack.pop(); - } - - index_stack.push(i); - } - - return results; - } -}; -``` - -## JavaScript -```javascript -var dailyTemperatures = function (temperatures) { - const results = Array(temperatures.length).fill(0) - const indexStack = [] - - temperatures.forEach((temperature, i) => { - while (indexStack.length > 0 && temperatures[indexStack.at(-1)] < temperature) { - results[indexStack.at(-1)] = i - indexStack.at(-1) - indexStack.pop() - } - - indexStack.push(i) - }) - - return results -}; -``` - -## C# -```c# -public class Solution -{ - public int[] DailyTemperatures(int[] temperatures) - { - var results = new int[temperatures.Length]; - var indexStack = new Stack(); - - for (var i = 0; i < temperatures.Length; i++) - { - while (indexStack.Count > 0 && temperatures[indexStack.Peek()] < temperatures[i]) - { - int index = indexStack.Pop(); - results[index] = i - index; - } - - indexStack.Push(i); - } - - return results; - } -} -``` - -## Go -### Solution 1: Using a 'slice' as stack -```go -func dailyTemperatures(temperatures []int) []int { - results := make([]int, len(temperatures)) - indexStack := []int{} - - for i, temperature := range temperatures { - for len(indexStack) > 0 && temperature > temperatures[indexStack[len(indexStack) - 1]] { - index := indexStack[len(indexStack) - 1] - results[index] = i - index - indexStack = indexStack[:len(indexStack) - 1] - } - - indexStack = append(indexStack, i) - } - - return results -} -``` - -### Solution 2: Using `GoDS` stack -```go -func dailyTemperatures(temperatures []int) []int { - results := make([]int, len(temperatures)) - indexStack := arraystack.New() - - for i, temperature := range temperatures { - for !indexStack.Empty() { - index, _ := indexStack.Peek(); - - if temperature <= temperatures[index.(int)] { - break - } - - indexStack.Pop() - results[index.(int)] = i - index.(int) - } - - indexStack.Push(i) - } - - return results -} -``` - -## Ruby -```ruby -def daily_temperatures(temperatures) - results = Array.new(temperatures.size, 0) - index_stack = [] - - temperatures.each_with_index do |temperature, i| - while !index_stack.empty? && temperatures[index_stack.last] < temperature - results[index_stack.last] = i - index_stack.last - index_stack.pop - end - - index_stack << i - end - - results -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/743-network-delay-time.md b/en/1-1000/743-network-delay-time.md deleted file mode 100644 index d13731f..0000000 --- a/en/1-1000/743-network-delay-time.md +++ /dev/null @@ -1,315 +0,0 @@ -# 743. Network Delay Time - Best Practices of LeetCode Solutions -LeetCode link: [743. Network Delay Time](https://leetcode.com/problems/network-delay-time), difficulty: **Medium**. - -## LeetCode description of "743. Network Delay Time" -You are given a network of `n` nodes, labeled from `1` to `n`. You are also given `times`, a list of travel times as directed edges `times[i] = (ui, vi, wi)`, where `ui` is the source node, `vi` is the target node, and `wi` is the time it takes for a signal to travel from source to target. - -We will send a signal from a given node `k`. Return _the **minimum** time it takes for all the n nodes to receive the signal_. If it is impossible for all the `n` nodes to receive the signal, return `-1`. - -### [Example 1] -![](../../images/examples/743_1.png) - -**Input**: `times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2` - -**Output**: `2` - -### [Example 2] -**Input**: `times = [[1,2,1]], n = 2, k = 1` - -**Output**: `1` - -### [Example 3] -**Input**: `times = [[1,2,1]], n = 2, k = 2` - -**Output**: `-1` - -### [Constraints] -- `1 <= k <= n <= 100` -- `1 <= times.length <= 6000` -- `times[i].length == 3` -- `1 <= ui, vi <= n` -- `ui != vi` -- `0 <= wi <= 100` -- All the pairs `(ui, vi)` are **unique**. (i.e., no multiple edges.) - -### [Hints] -
- Hint 1 - We visit each node at some time, and if that time is better than the fastest time we've reached this node, we travel along outgoing edges in sorted order. Alternatively, we could use Dijkstra's algorithm. -
- -## Intuition -We can solve it via both **Bellman-Ford algorithm** and **Dijkstra's algorithm**. - -### Bellman-Ford Algorithm -Here is an animation about _Bellman-Ford algorithm_: - -![](../../images/graph_Bellman-Ford_algorithm_animation.gif) - -* `Bellman-Ford algorithm` has less code and can handle the situation of **negative** edge weights, but it is slower than `Dijkstra's algorithm` if it is not optimized. -The following code will introduce how to optimize. - -* `Dijkstra's algorithm` always takes the shortest path, so it is more efficient, but it requires writing more code and it cannot handle the situation of **negative** edge weights. - -For a detailed description of **Dijkstra's algorithm**, please refer to [1514. Path with Maximum Probability](../1001-2000/1514-path-with-maximum-probability.md). - -### Common graph theory algorithm comparison table -|Algorithm name|Main application scenarios|Optimization methods|Importance|Difficulty|min_
distances|Negative weights|Additional application scenarios| -|--------------|--------------------------|--------------------|----------|----------|-------------|----------------|--------------------------------| -|[Depth-first search](./797-all-paths-from-source-to-target.md) |Traverse a graph |No need |Very important|Easy |No need |Can handle|| -|[Breath-first search](../1001-2000/1971-find-if-path-exists-in-graph.md) |Traverse a graph |No need |Very important|Easy |No need |Can handle|Single-Source Shortest Path if No Weight| -|[UnionFind, aka disjoint-set](./684-redundant-connection.md) |Graph Connectivity |Path Compression |Very important|Medium |No need |Can handle|[Directed Graph Cycle Detection](./685-redundant-connection-ii.md)| -|[Prim's algorithm](../1001-2000/1584-min-cost-to-connect-all-points.md) |Minimum Spanning Tree |Heap Sort to Simplify|Important |Medium |Used |Can handle|| -|[Kruskal's algorithm](../1001-2000/1584-min-cost-to-connect-all-points-2.md) |Minimum Spanning Tree |No need |Important |Relatively hard|No need|Can handle|| -|[Dijkstra's algorithm](../1001-2000/1514-path-with-maximum-probability.md) |Single-Source Shortest Path|Heap Sort |Very important|Relatively hard|Used |Cannot handle|| -|[A* search algorithm](./752-open-the-lock.md) |Single-Source Shortest Path|Built-in Heap Sort |Very important|Medium |No need|It depends|| -|[Bellman-Ford algorithm](./743-network-delay-time.md) |Single-Source Shortest Path|Queue-Improved |Very Important|Easy |Used |Can handle|[Detect Negative Cycles](https://www.geeksforgeeks.org/detect-negative-cycle-graph-bellman-ford/),
[Shortest Hop-Bounded Paths](./787-cheapest-flights-within-k-stops.md)| -|[Floyd–Warshall](../1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md)|Multi-Source Shortest Path |No need |Less important|Relatively hard|Used |Can handle|| - -## Complexity -**V**: vertex count, **E**: Edge count. - -### Bellman-Ford algorithm -* Time: `O(V * E)`. -* Space: `O(V)`. - -### Queue-improved Bellman-Ford algorithm (also known as `Shortest Path Faster Algorithm` abbreviated as `SPFA`) -* Time: `O(V * X)` (`X` < `E`). -* Space: `O(V + E)`. - -### Dijkstra's algorithm using `heap sort` -* Time: `O(E * log(E))`. -* Space: `O(V + E)`. - -## Python -### Bellman-Ford algorithm (slow, yet below, I will introduce how to improve its efficiency) -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - - for _ in range(n - 1): - for source_node, target_node, time in edges: # process edges directly - if min_times[source_node] == float('inf'): - continue - - target_time = time + min_times[source_node] - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -A very similar question: [787. Cheapest Flights Within K Stops](./787-cheapest-flights-within-k-stops.md), but if you use the above code, it will not be accepted by LeetCode. - -You can try to solve `787. Cheapest Flights Within K Stops` first, then read on. - -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - - for _ in range(n - 1): - # If you remove the next line and always use `min_times`, it can also be accepted. - # But if you print `min_times`, you may see different result. Please try it. - # The values of `min_times` modified in this loop will affect the subsequent `min_times` items in the same loop. - # Please work on `problem 787`: https://leetcode.com/problems/cheapest-flights-within-k-stops/ to better understand this. - min_times_clone = min_times.copy() # addition 1 - - for source_node, target_node, time in edges: # process edges directly - if min_times_clone[source_node] == float('inf'): # change 1 - continue - - target_time = time + min_times_clone[source_node] # change 2 - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### A variant of Bellman-Ford algorithm, which can be used to improve the efficiency of Bellman-Ford algorithm below -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - - for source, target, time in edges: # process nodes first, then their edges - node_to_pairs[source].add((target, time)) - - for _ in range(n - 1): - for node, min_time in enumerate(min_times): # process nodes first - if min_time == float('inf'): - continue - - for target_node, time in node_to_pairs[node]: # process edges of the node - target_time = time + min_time - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### Queue-improved Bellman-Ford algorithm (also known as `Shortest Path Faster Algorithm` abbreviated as `SPFA`) -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - - for source, target, time in edges: # process nodes first, then their edges - node_to_pairs[source].add((target, time)) - - updated_nodes = set([start_node]) # added 1 - - for _ in range(n - 1): - nodes = updated_nodes.copy() # added 3 - updated_nodes.clear() # added 4 - - for node in nodes: # changed 1 - for target_node, time in node_to_pairs[node]: # process edges of the node - target_time = time + min_times[node] - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - updated_nodes.add(target_node) # added 2 - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### Dijkstra's algorithm using `heap sort` (without `visited`) -```python -import heapq - -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - - for source, target, time in edges: - node_to_pairs[source].add((target, time)) - - priority_queue = [(0, start_node)] - - while priority_queue: - current_time, current_node = heapq.heappop(priority_queue) - - for target_node, time in node_to_pairs[current_node]: - target_time = time + current_time - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - heapq.heappush(priority_queue, (target_time, target_node)) - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### Dijkstra's algorithm using `heap sort` (with `visited`) -```python -import heapq - -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - visited = [False] * (n + 1) # added 1 - - for source, target, time in edges: - node_to_pairs[source].add((target, time)) - - priority_queue = [(0, start_node)] - - while priority_queue: - current_time, current_node = heapq.heappop(priority_queue) - - if visited[current_node]: # added 3 - continue - - visited[current_node] = True # added 2 - - for target_node, time in node_to_pairs[current_node]: - if visited[target_node]: # added 4 - continue - - target_time = time + current_time - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - heapq.heappush(priority_queue, (target_time, target_node)) - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/752-open-the-lock.md b/en/1-1000/752-open-the-lock.md deleted file mode 100644 index 79f7493..0000000 --- a/en/1-1000/752-open-the-lock.md +++ /dev/null @@ -1,239 +0,0 @@ -# 752. Open the Lock - Best Practices of LeetCode Solutions -LeetCode link: [752. Open the Lock](https://leetcode.com/problems/open-the-lock), difficulty: **Medium**. - -## LeetCode description of "752. Open the Lock" -You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: `'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'`. The wheels can rotate freely and wrap around: for example we can turn `9` to be `0`, or `0` to be `9`. Each move consists of turning one wheel one slot. - -The lock initially starts at `0000`, a string representing the state of the 4 wheels. - -You are given a list of `deadends` dead ends, meaning if the lock displays any of these codes, the wheels of the lock will stop turning and you will be unable to open it. - -Given a `target` representing the value of the wheels that will unlock the lock, return _the **minimum total number** of turns required to open the lock, or `-1` if it is impossible_. - -### [Example 1] -**Input**: `deadends = ["0201","0101","0102","1212","2002"], target = "0202"` - -**Output**: `6` - -**Explanation**: -``` -A sequence of valid moves would be "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202". -Note that a sequence like "0000" -> "0001" -> "0002" -> "0102" -> "0202" would be invalid, -because the wheels of the lock become stuck after the display becomes the dead end "0102". -``` - -### [Example 2] -**Input**: `deadends = ["8888"], target = "0009"` - -**Output**: `1` - -**Explanation**: -``` -We can turn the last wheel in reverse to move from "0000" -> "0009". -``` - -### [Example 3] -**Input**: `["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"` - -**Output**: `-1` - -**Explanation**: `We cannot reach the target without getting stuck.` - -### [Constraints] -- `1 <= deadends.length <= 500` -- `deadends[i].length == 4` -- `target.length == 4` -- `target` **will not be** in the list `deadends`. -- `target` and `deadends[i]` consist of digits only. - -### [Hints] -
- Hint 1 - We can think of this problem as a shortest path problem on a graph: there are `10000` nodes (strings `'0000'` to `'9999'`), and there is an edge between two nodes if they differ in one digit, that digit differs by 1 (wrapping around, so `'0'` and `'9'` differ by 1), and if *both* nodes are not in `deadends`. -
- -## Intuition -We can think of this problem as a shortest path problem on a graph: there are `10000` nodes (strings `'0000'` to `'9999'`), and there is an edge between two nodes if they differ in one digit, that digit differs by 1 (wrapping around, so `'0'` and `'9'` differ by 1), and if *both* nodes are not in `deadends`. - -### Solution 1: Breadth-First Search -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **Breadth-First Search** can be thought of as visiting vertices in rounds and rounds. Actually, whenever you see a question is about - getting `minimum number` of something of a graph, `Breadth-First Search` would probably help. - -* `Breadth-First Search` emphasizes first-in-first-out, so a **queue** is needed. - -### Solution 2: A* (A-Star) Search Algorithm - -**A-Star Algorithm** can be used to improve the performance of **Breadth-First Search Algorithm**. - -**Breadth-First Search** treats each vertex equally, which inevitably leads to poor performance. - -The _A* (A-star) search algorithm_ calculates the **distance** between each `vertex` and the `target vertex`, and **prioritizes vertices with closer distances**, which is equivalent to indicating which vertex to process next, so the performance is greatly improved! - -_A* (A-star) search algorithm_ is similar to _Dijkstra's algorithm_, but the `target vertex` of _A* (A-star) search algorithm_ is clear, while that of _Dijkstra's algorithm_ is not. _Dijkstra's algorithm_ calculates the `distance` from the `starting vertex` to the `vertex` it reaches. - -#### A* (A-Star) Search Algorithm Has Two (or Three) Key Actions -1. Use `priority_queue`. -2. The **heuristic function** for calculating `distance` should be **carefully designed** (poor design will lead to **subtle** errors in the results). -3. In special cases, simply using `distance` as the sorting basis of `priority_queue` is not enough, and it is also necessary to **adjust** (for example, add it to the `number of steps` variable value) to make the last few steps accurate (not involved in this example, yet in this one [1197. Minimum Knight Moves](https://leetcode.com/problems/minimum-knight-moves/)). - -## Complexity -> `N` is the length of `deadends`. - -### Solution 1: Breadth-First Search -* Time: `O(10^4)`. -* Space: `O(N)`. - -### Solution 2: A* (A-Star) Search Algorithm -* Time: `O(5 * 4 * 4 * 2 + N)`. -* Space: `O(N)`. - -## Python -### Solution 1: Breadth-First Search -```python -class Solution: - def openLock(self, deadends: List[str], target_digits: str) -> int: - if '0000' == target_digits: - return 0 - - self.deadends = set(deadends) - if '0000' in deadends: - return -1 - - self.queue = deque(['0000']) - self.deadends.add('0000') - self.target_digits = target_digits - result = 0 - - while self.queue: - result += 1 - queue_size = len(self.queue) - - for _ in range(queue_size): - digits = self.queue.popleft() - - if self.turn_one_slot(digits): - return result - - return -1 - - def turn_one_slot(self, digits): - for i in range(len(digits)): - for digit in closest_digits(int(digits[i])): - new_digits = f'{digits[:i]}{digit}{digits[i + 1:]}' - - if new_digits == self.target_digits: - return True - - if new_digits in self.deadends: - continue - - self.queue.append(new_digits) - self.deadends.add(new_digits) - - -def closest_digits(digit): - if digit == 0: - return (9, 1) - - if digit == 9: - return (8, 0) - - return (digit - 1, digit + 1) -``` - -### Solution 2: A* (A-Star) Search Algorithm -```python -class Solution: - def openLock(self, deadends: List[str], target_digits: str) -> int: - if '0000' == target_digits: - return 0 - - deadends = set(deadends) - if '0000' in deadends: - return -1 - - self.target_digits = target_digits - - priority_queue = [(self.distance('0000'), '0000', 0)] - - while priority_queue: - _, digits, turns = heapq.heappop(priority_queue) - - for i in range(4): - for digit in closest_digits(int(digits[i])): - new_digits = f'{digits[:i]}{digit}{digits[i + 1:]}' - - if new_digits == target_digits: - return turns + 1 - - if new_digits in deadends: - continue - - heapq.heappush( - priority_queue, - (self.distance(new_digits), new_digits, turns + 1) - ) - deadends.add(new_digits) - - return -1 - - def distance(self, digits): - result = 0 - - # 0 1 2 3 4 5 6 7 8 9 - # 0 1 2 3 4 5 6 7 8 9 - # 0 1 2 3 4 5 6 7 8 9 - # 0 1 2 3 4 5 6 7 8 9 - for i in range(4): - # 'Euclidean Distance' is widely used in 'A* Algorithm'. - result += abs(int(self.target_digits[i]) - int(digits[i])) ** 2 - - return result ** 0.5 - - -def closest_digits(digit): - if digit == 0: - return (9, 1) - - if digit == 9: - return (8, 0) - - return (digit - 1, digit + 1) -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/787-cheapest-flights-within-k-stops.md b/en/1-1000/787-cheapest-flights-within-k-stops.md deleted file mode 100644 index 4caf15e..0000000 --- a/en/1-1000/787-cheapest-flights-within-k-stops.md +++ /dev/null @@ -1,125 +0,0 @@ -# 787. Cheapest Flights Within K Stops - Best Practices of LeetCode Solutions -LeetCode link: [787. Cheapest Flights Within K Stops](https://leetcode.com/problems/cheapest-flights-within-k-stops), difficulty: **Medium**. - -## LeetCode description of "787. Cheapest Flights Within K Stops" -There are `n` cities connected by some number of flights. You are given an array `flights` where `flights[i] = [from_i, to_i, price_i]` indicates that there is a flight from city `from_i` to city `to_i` with cost `price_i`. - -You are also given three integers `src`, `dst`, and `k`, return _**the cheapest price** from `src` to `dst` with at most `k` stops_. If there is no such route, return `-1`. - -### [Example 1] -![](../../images/examples/787_1.png) - -**Input**: `n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1` - -**Output**: `700` - -**Explanation**: -``` -The graph is shown above. -The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700. -Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops. -``` - -### [Example 2] -**Input**: `n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1` - -**Output**: `200` - -**Explanation**: -``` -The graph is shown above. -The optimal path with at most 1 stop from city 0 to 2 is marked in red and has cost 100 + 100 = 200. -``` - -### [Example 3] -**Input**: `n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 0` - -**Output**: `500` - -**Explanation**: -``` -The graph is shown above. -The optimal path with no stops from city 0 to 2 is marked in red and has cost 500. -``` - -### [Constraints] -- `1 <= n <= 100` -- `0 <= flights.length <= (n * (n - 1) / 2)` -- `flights[i].length == 3` -- `0 <= from_i, to_i < n` -- `from_i != to_i` -- `1 <= price_i <= 10000` -- There will not be any multiple flights between two cities. -- `0 <= src, dst, k < n` -- `src != dst` - -## Intuition -We can solve it via **Bellman-Ford algorithm**. - -For a detailed introduction to `Bellman-Ford algorithm`, please refer to [743. Network Delay Time](./743-network-delay-time.md). - -## Complexity -**V**: vertex count, **E**: Edge count. - -* Time: `O(K * E)`. -* Space: `O(V)`. - -## Python -```python -class Solution: - def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int: - min_costs = [float('inf')] * n - min_costs[src] = 0 - - for _ in range(k + 1): - min_costs_clone = min_costs.copy() - - for from_city, to_city, price in flights: - if min_costs_clone[from_city] == float('inf'): - continue - - cost = min_costs_clone[from_city] + price - - if cost < min_costs[to_city]: - min_costs[to_city] = cost - - if min_costs[dst] == float('inf'): - return -1 - - return min_costs[dst] -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/797-all-paths-from-source-to-target.md b/en/1-1000/797-all-paths-from-source-to-target.md deleted file mode 100644 index 81340fb..0000000 --- a/en/1-1000/797-all-paths-from-source-to-target.md +++ /dev/null @@ -1,865 +0,0 @@ -# 797. All Paths From Source to Target - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [797. All Paths From Source to Target - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/797-all-paths-from-source-to-target) for a better experience! - -LeetCode link: [797. All Paths From Source to Target](https://leetcode.com/problems/all-paths-from-source-to-target), difficulty: **Medium**. - -## LeetCode description of "797. All Paths From Source to Target" - -Given a directed acyclic graph (**DAG**) of `n` nodes labeled from `0` to `n - 1`, find all possible paths from node `0` to node `n - 1` and return them in **any order**. - -The graph is given as follows: `graph[i]` is a list of all nodes you can visit from node `i` (i.e., there is a directed edge from node `i` to node `graph[i][j]`). - -### [Example 1] - -![](../../images/examples/797_1.jpg) - -**Input**: `graph = [[1,2],[3],[3],[]]` - -**Output**: `[[0,1,3],[0,2,3]]` - -**Explanation**: - -

There are two paths: 0 -> 1 -> 3 and 0 -> 2 -> 3.

- - -### [Example 2] - -![](../../images/examples/797_2.jpg) - -**Input**: `graph = [[4,3,1],[3,2,4],[3],[4],[]]` - -**Output**: `[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]` - -### [Constraints] - -- `n == graph.length` -- `2 <= n <= 15` -- `0 <= graph[i][j] < n` -- `graph[i][j] != i` (i.e., there will be no self-loops). -- All the elements of `graph[i]` are **unique**. -- The input graph is **guaranteed** to be a **DAG**. - -## Intuition 1 - - - -## Pattern of "Depth-First Search" - -**Depth-First Search (DFS)** is a classic graph traversal algorithm characterized by its **"go as deep as possible"** approach when exploring branches of a graph. Starting from the initial vertex, DFS follows a single path as far as possible until it reaches a vertex with no unvisited adjacent nodes, then backtracks to the nearest branching point to continue exploration. This process is implemented using **recursion** or an **explicit stack (iterative method)**, resulting in a **Last-In-First-Out (LIFO)** search order. As a result, DFS can quickly reach deep-level nodes far from the starting point in unweighted graphs. - -**Comparison with BFS**: - -1. **Search Order**: DFS prioritizes depth-wise exploration, while Breadth-First Search (BFS) expands layer by layer, following a **First-In-First-Out (FIFO)** queue structure. -2. **Use Cases**: DFS is better suited for strongly connected components or backtracking problems (e.g., finding all paths in a maze), whereas BFS excels at finding the shortest path (in unweighted graphs) or exploring neighboring nodes (e.g., friend recommendations in social networks). - -**Unique Aspects of DFS**: - -- **Incompleteness**: If the graph is infinitely deep or contains cycles (without visited markers), DFS may fail to terminate, whereas BFS always finds the shortest path (in unweighted graphs). -- **"One-path deep-dive"** search style makes it more flexible for backtracking, pruning, or path recording, but it may also miss near-optimal solutions. - -In summary, DFS reveals the vertical structure of a graph through its depth-first strategy. Its inherent backtracking mechanism, combined with the natural use of a stack, makes it highly effective for path recording and state-space exploration. However, precautions must be taken to handle cycles and the potential absence of optimal solutions. - -## Step by Step Solutions - -1. Initialize an empty list `paths` to store all valid paths found. -2. Initialize a stack to manage the DFS traversal. Each element on the stack will store a pair (or tuple) containing the current `node` and the `path` taken to reach that node. -3. Push the starting state onto the stack: the initial node `0` and an empty path list (e.g., `(0, [])`). -4. While the stack is not empty: - - Pop the top element from the stack, retrieving the current `node` and its associated `path`. - - Create a `currentPath` list by appending the current `node` to the `path` popped from the stack. This represents the path leading up to and including the current node. - - Check if the current `node` is the target node (`n - 1`, where `n` is the total number of nodes). - - If it is the target node, add the `currentPath` to the `paths` list, as a complete path from source to target has been found. - - If it is not the target node, iterate through all `neighbor` nodes accessible from the current `node` (i.e., iterate through `graph[node]`). - - For each `neighbor`, push a new pair onto the stack: the `neighbor` node and the `currentPath`. This prepares the traversal to explore paths extending from the neighbor. -5. After the loop finishes (stack is empty), return the `paths` list containing all discovered paths from node `0` to node `n - 1`. - -## Complexity - -- Time complexity: `Too complex`. -- Space complexity: `Too complex`. - -## Python - -```python -class Solution: - def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: - paths = [] - stack = [(0, [])] - - while stack: - node, path = stack.pop() - - if node == len(graph) - 1: - paths.append(path + [node]) - continue - - for target_node in graph[node]: - stack.append((target_node, path + [node])) - - return paths -``` - -## Java - -```java -class Solution { - public List> allPathsSourceTarget(int[][] graph) { - List> paths = new ArrayList<>(); - // Each element in the stack is a pair: (current_node, current_path) - Stack>> stack = new Stack<>(); - List initialPath = new ArrayList<>(); - stack.push(new Pair<>(0, initialPath)); - - int targetNode = graph.length - 1; - - while (!stack.isEmpty()) { - var current = stack.pop(); - int node = current.getKey(); - var path = current.getValue(); - - var nextPath = new ArrayList<>(path); - nextPath.add(node); - - if (node == targetNode) { - paths.add(nextPath); - continue; - } - - for (int neighbor : graph[node]) { - stack.push(new Pair<>(neighbor, nextPath)); - } - } - - return paths; - } -} - -``` - -## C++ - -```cpp -class Solution { -public: - vector> allPathsSourceTarget(vector>& graph) { - vector> paths; - // Stack stores pairs of (current_node, current_path) - stack>> s; - s.push({0, {}}); // Start at node 0 with an empty path initially - - int targetNode = graph.size() - 1; - - while (!s.empty()) { - auto node_path = s.top(); - s.pop(); - int node = node_path.first; - vector path = node_path.second; - - // Add the current node to the path - path.push_back(node); - - if (node == targetNode) { - paths.push_back(path); // Found a path to the target - continue; - } - - // Explore neighbors - for (int neighbor : graph[node]) { - s.push({neighbor, path}); - } - } - - return paths; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[][]} graph - * @return {number[][]} - */ -var allPathsSourceTarget = function(graph) { - const paths = []; - // Stack stores arrays: [current_node, current_path] - const stack = [[0, []]]; // Start at node 0 with an empty path - const targetNode = graph.length - 1; - - while (stack.length > 0) { - const [node, path] = stack.pop(); - - // Create the new path by appending the current node - const currentPath = [...path, node]; - - if (node === targetNode) { - paths.push(currentPath); // Found a path - continue; - } - - // Explore neighbors - for (const neighbor of graph[node]) { - stack.push([neighbor, currentPath]); // Push neighbor and the path so far - } - } - - return paths; -}; - -``` - -## C# - -```csharp -public class Solution { - public IList> AllPathsSourceTarget(int[][] graph) - { - var paths = new List>(); - // Stack stores tuples: (current_node, current_path) - var stack = new Stack<(int node, List path)>(); - stack.Push((0, new List())); // Start at node 0 - - int targetNode = graph.Length - 1; - - while (stack.Count > 0) - { - var (node, path) = stack.Pop(); - - var currentPath = new List(path); - currentPath.Add(node); - - if (node == targetNode) - { - paths.Add(currentPath); // Found a path - continue; - } - - // Explore neighbors - foreach (int neighbor in graph[node]) - { - stack.Push((neighbor, currentPath)); // Push neighbor and the path so far - } - } - - return paths; - } -} -``` - -## Go - -```go -type StackItem struct { - Node int - Path []int -} - -func allPathsSourceTarget(graph [][]int) [][]int { - var paths [][]int - stack := []StackItem{{Node: 0, Path: []int{}}} // Start at node 0 - - targetNode := len(graph) - 1 - - for len(stack) > 0 { - currentItem := stack[len(stack) - 1] // Pop from stack - stack = stack[:len(stack) - 1] - - node := currentItem.Node - path := currentItem.Path - - newPath := append([]int(nil), path...) - newPath = append(newPath, node) - - if node == targetNode { - paths = append(paths, newPath) // Found a path - continue - } - - for _, neighbor := range graph[node] { - stack = append(stack, StackItem{Node: neighbor, Path: newPath}) - } - } - - return paths -} -``` - -## Ruby - -```ruby -# @param {Integer[][]} graph -# @return {Integer[][]} -def all_paths_source_target(graph) - paths = [] - # Stack stores arrays: [current_node, current_path] - stack = [[0, []]] # Start at node 0 with an empty path - target_node = graph.length - 1 - - while !stack.empty? - node, path = stack.pop - - # Create the new path by appending the current node - current_path = path + [node] - - if node == target_node - paths << current_path # Found a path - next - end - - # Explore neighbors - graph[node].each do |neighbor| - stack.push([neighbor, current_path]) - end - end - - paths -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - - - -## Pattern of "Depth-First Search" - -**Depth-First Search (DFS)** is a classic graph traversal algorithm characterized by its **"go as deep as possible"** approach when exploring branches of a graph. Starting from the initial vertex, DFS follows a single path as far as possible until it reaches a vertex with no unvisited adjacent nodes, then backtracks to the nearest branching point to continue exploration. This process is implemented using **recursion** or an **explicit stack (iterative method)**, resulting in a **Last-In-First-Out (LIFO)** search order. As a result, DFS can quickly reach deep-level nodes far from the starting point in unweighted graphs. - -**Comparison with BFS**: - -1. **Search Order**: DFS prioritizes depth-wise exploration, while Breadth-First Search (BFS) expands layer by layer, following a **First-In-First-Out (FIFO)** queue structure. -2. **Use Cases**: DFS is better suited for strongly connected components or backtracking problems (e.g., finding all paths in a maze), whereas BFS excels at finding the shortest path (in unweighted graphs) or exploring neighboring nodes (e.g., friend recommendations in social networks). - -**Unique Aspects of DFS**: - -- **Incompleteness**: If the graph is infinitely deep or contains cycles (without visited markers), DFS may fail to terminate, whereas BFS always finds the shortest path (in unweighted graphs). -- **"One-path deep-dive"** search style makes it more flexible for backtracking, pruning, or path recording, but it may also miss near-optimal solutions. - -In summary, DFS reveals the vertical structure of a graph through its depth-first strategy. Its inherent backtracking mechanism, combined with the natural use of a stack, makes it highly effective for path recording and state-space exploration. However, precautions must be taken to handle cycles and the potential absence of optimal solutions. - -## Pattern of "Recursion" - -Recursion is an important concept in computer science and mathematics, which refers to the method by which a function calls itself **directly or indirectly** in its definition. - -### The core idea of ​​recursion - -- **Self-call**: A function calls itself during execution. -- **Base case**: Equivalent to the termination condition. After reaching the base case, the result can be returned without recursive calls to prevent infinite loops. -- **Recursive step**: The step by which the problem gradually approaches the "base case". - -## Step by Step Solutions - -1. Initialize an empty list `paths` to store all the valid paths found from source to target. -2. Define a recursive Depth-First Search (DFS) function, say `dfs`, that takes the current `node` and the `currentPath` (a list of nodes visited so far to reach the current node) as input. -3. Inside the `dfs` function: - a. Create a new path list by appending the current `node` to the `currentPath`. Let's call this `newPath`. - b. Check if the current `node` is the target node (`n - 1`, where `n` is the total number of nodes). - i. If it is the target node, it means we've found a complete path. Add `newPath` to the main `paths` list and return from this recursive call. - c. If the current `node` is not the target node, iterate through all `neighbor` nodes accessible from the current `node` (i.e., iterate through `graph[node]`). - i. For each `neighbor`, make a recursive call to `dfs` with the `neighbor` as the new current node and `newPath` as the path taken to reach it (`dfs(neighbor, newPath)`). -4. Start the process by calling the `dfs` function with the source node `0` and an empty initial path (`dfs(0, [])`). -5. After the initial `dfs` call completes, return the `paths` list containing all discovered paths. - -## Complexity - -- Time complexity: `Too complex`. -- Space complexity: `Too complex`. - -## Python - -```python -class Solution: - def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: - self.paths = [] - self.graph = graph - self.target = len(graph) - 1 - - self.dfs(0, []) # Start DFS from node 0 with an empty initial path - - return self.paths - - def dfs(self, node, path): - current_path = path + [node] - - if node == self.target: # Base case - self.paths.append(current_path) - return - - for neighbor in self.graph[node]: # Recursive step: Explore neighbors - self.dfs(neighbor, current_path) -``` - -## Java - -```java -class Solution { - private List> paths; - private int[][] graph; - private int targetNode; - - public List> allPathsSourceTarget(int[][] graph) { - this.paths = new ArrayList<>(); - this.graph = graph; - this.targetNode = graph.length - 1; - - List initialPath = new ArrayList<>(); - dfs(0, initialPath); // Start DFS from node 0 with an empty initial path - - return paths; - } - - private void dfs(int node, List currentPath) { - List newPath = new ArrayList<>(currentPath); - newPath.add(node); - - if (node == targetNode) { // Base case - paths.add(newPath); - return; - } - - for (int neighbor : graph[node]) { // Recursive step: Explore neighbors - dfs(neighbor, newPath); - } - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> allPathsSourceTarget(vector>& graph) { - _graph = graph; - - vector initial_path; // Empty initial path - dfs(0, initial_path); // Start DFS from node 0 - - return _paths; - } - -private: - vector> _paths; - vector> _graph; - - void dfs(int node, vector current_path) { - current_path.push_back(node); - - if (node == _graph.size() - 1) { // Base case - _paths.push_back(current_path); - return; - } - - for (int neighbor : _graph[node]) { // Recursive step: Explore neighbors - dfs(neighbor, current_path); - } - } -}; -``` - -## JavaScript - -```javascript -let paths -let graph - -var allPathsSourceTarget = function (graph_) { - paths = [] - graph = graph_ - - dfs(0, []) - - return paths -} - -function dfs(node, currentPath) { - const newPath = [...currentPath, node] - - if (node === graph.length - 1) { // Base case - paths.push(newPath) - return - } - - for (const neighbor of graph[node]) { // Recursive step: Explore neighbors - dfs(neighbor, newPath) - } -} - -``` - -## C# - -```csharp -public class Solution -{ - private IList> paths; - private int[][] graph; - private int targetNode; - - public IList> AllPathsSourceTarget(int[][] graph) - { - this.paths = new List>(); - this.graph = graph; - this.targetNode = graph.Length - 1; - - Dfs(0, new List()); - - return paths; - } - - private void Dfs(int node, List currentPath) - { - var newPath = new List(currentPath); - newPath.Add(node); - - if (node == targetNode) // Base case - { - paths.Add(newPath); - return; - } - - foreach (int neighbor in graph[node]) // Recursive step: Explore neighbors - { - Dfs(neighbor, newPath); - } - } -} -``` - -## Go - -```go -var ( - paths [][]int - graph [][]int - targetNode int -) - -func allPathsSourceTarget(graph_ [][]int) [][]int { - paths = [][]int{} - graph = graph_ - targetNode = len(graph) - 1 - - dfs(0, []int{}) - - return paths -} - -func dfs(node int, currentPath []int) { - newPath := append([]int(nil), currentPath...) - newPath = append(newPath, node) - - if node == targetNode { // Base case - paths = append(paths, newPath) - return - } - - for _, neighbor := range graph[node] { // Recursive step: Explore neighbors - dfs(neighbor, newPath) - } -} -``` - -## Ruby - -```ruby -def all_paths_source_target(graph) - @paths = [] - @graph = graph - - dfs(0, []) - - @paths -end - -def dfs(node, current_path) - new_path = current_path + [node] - - if node == @graph.size - 1 # Base case - @paths << new_path - return - end - - @graph[node].each do |neighbor| # Recursive step: Explore neighbors - dfs(neighbor, new_path) - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 3 - - - -## Pattern of "Depth-First Search" - -**Depth-First Search (DFS)** is a classic graph traversal algorithm characterized by its **"go as deep as possible"** approach when exploring branches of a graph. Starting from the initial vertex, DFS follows a single path as far as possible until it reaches a vertex with no unvisited adjacent nodes, then backtracks to the nearest branching point to continue exploration. This process is implemented using **recursion** or an **explicit stack (iterative method)**, resulting in a **Last-In-First-Out (LIFO)** search order. As a result, DFS can quickly reach deep-level nodes far from the starting point in unweighted graphs. - -**Comparison with BFS**: - -1. **Search Order**: DFS prioritizes depth-wise exploration, while Breadth-First Search (BFS) expands layer by layer, following a **First-In-First-Out (FIFO)** queue structure. -2. **Use Cases**: DFS is better suited for strongly connected components or backtracking problems (e.g., finding all paths in a maze), whereas BFS excels at finding the shortest path (in unweighted graphs) or exploring neighboring nodes (e.g., friend recommendations in social networks). - -**Unique Aspects of DFS**: - -- **Incompleteness**: If the graph is infinitely deep or contains cycles (without visited markers), DFS may fail to terminate, whereas BFS always finds the shortest path (in unweighted graphs). -- **"One-path deep-dive"** search style makes it more flexible for backtracking, pruning, or path recording, but it may also miss near-optimal solutions. - -In summary, DFS reveals the vertical structure of a graph through its depth-first strategy. Its inherent backtracking mechanism, combined with the natural use of a stack, makes it highly effective for path recording and state-space exploration. However, precautions must be taken to handle cycles and the potential absence of optimal solutions. - -## Step by Step Solutions - -1. Initialize an empty list `paths` to store all valid paths found from the source to the target. -2. Create a mutable list `path` to track the current path being explored, initially containing only the source node `0`. -3. Implement a recursive DFS function that explores paths using backtracking: - - Base case: If the current node is the target node (`n-1`), make a copy of the current path and add it to the `paths` list. - - Recursive step: For each neighbor of the current node: - - Add the neighbor to the current path. - - Recursively call the DFS function with this neighbor. - - After the recursive call returns, remove the neighbor from the path (backtrack). -4. Start the DFS from the source node `0`. -5. Return the collected `paths` after the DFS completes. - -## Complexity - -- Time complexity: `Too complex`. -- Space complexity: `Too complex`. - -## Python - -```python -class Solution: - def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: - self.paths = [] - self.graph = graph - self.path = [0] # Important - - self.dfs(0) - - return self.paths - - def dfs(self, node): - if node == len(self.graph) - 1: - self.paths.append(self.path.copy()) # Important - return - - for neighbor in self.graph[node]: - self.path.append(neighbor) # Important - self.dfs(neighbor) - self.path.pop() # Important - -``` - -## Java - -```java -class Solution { - private List> paths = new ArrayList<>(); - private List path = new ArrayList<>(List.of(0)); // Important - start with node 0 - private int[][] graph; - - public List> allPathsSourceTarget(int[][] graph) { - this.graph = graph; - - dfs(0); - - return paths; - } - - private void dfs(int node) { - if (node == graph.length - 1) { // Base case - paths.add(new ArrayList<>(path)); // Important - make a copy - return; - } - - for (int neighbor : graph[node]) { // Recursive step - path.add(neighbor); // Important - dfs(neighbor); - path.remove(path.size() - 1); // Important - backtrack - } - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> allPathsSourceTarget(vector>& graph) { - _graph = graph; - _path = {0}; // Important - start with node 0 - - dfs(0); - - return _paths; - } - -private: - vector> _paths; - vector> _graph; - vector _path; - - void dfs(int node) { - if (node == _graph.size() - 1) { // Base case - _paths.push_back(_path); // Important - copy is made automatically - return; - } - - for (int neighbor : _graph[node]) { // Recursive step - _path.push_back(neighbor); // Important - dfs(neighbor); - _path.pop_back(); // Important - backtrack - } - } -}; - -``` - -## JavaScript - -```javascript -/** - * @param {number[][]} graph - * @return {number[][]} - */ -var allPathsSourceTarget = function(graph) { - const paths = []; - const path = [0]; // Important - start with node 0 - - function dfs(node) { - if (node === graph.length - 1) { // Base case - paths.push([...path]); // Important - make a copy - return; - } - - for (const neighbor of graph[node]) { // Recursive step - path.push(neighbor); // Important - dfs(neighbor); - path.pop(); // Important - backtrack - } - } - - dfs(0); - - return paths; -}; -``` - -## C# - -```csharp -public class Solution -{ - private IList> paths = new List>(); - private List path = new List { 0 }; // Important - start with node 0 - private int[][] graph; - - public IList> AllPathsSourceTarget(int[][] graph) - { - this.graph = graph; - - Dfs(0); - - return paths; - } - - private void Dfs(int node) - { - if (node == graph.Length - 1) - { // Base case - paths.Add(new List(path)); // Important - make a copy - return; - } - - foreach (int neighbor in graph[node]) - { // Recursive step - path.Add(neighbor); // Important - Dfs(neighbor); - path.RemoveAt(path.Count - 1); // Important - backtrack - } - } -} -``` - -## Go - -```go -func allPathsSourceTarget(graph [][]int) [][]int { - paths := [][]int{} - path := []int{0} // Important - start with node 0 - - var dfs func(int) - dfs = func(node int) { - if node == len(graph) - 1 { // Base case - // Important - make a deep copy of the path - paths = append(paths, append([]int(nil), path...)) - return - } - - for _, neighbor := range graph[node] { // Recursive step - path = append(path, neighbor) // Important - dfs(neighbor) - path = path[:len(path) - 1] // Important - backtrack - } - } - - dfs(0) - - return paths -} -``` - -## Ruby - -```ruby -# @param {Integer[][]} graph -# @return {Integer[][]} -def all_paths_source_target(graph) - @paths = [] - @graph = graph - @path = [0] # Important - start with node 0 - - dfs(0) - - @paths -end - -def dfs(node) - if node == @graph.length - 1 # Base case - @paths << @path.clone # Important - make a copy - return - end - - @graph[node].each do |neighbor| # Recursive step - @path << neighbor # Important - dfs(neighbor) - @path.pop # Important - backtrack - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [797. All Paths From Source to Target - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/797-all-paths-from-source-to-target). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/827-making-a-large-island.md b/en/1-1000/827-making-a-large-island.md deleted file mode 100644 index a778880..0000000 --- a/en/1-1000/827-making-a-large-island.md +++ /dev/null @@ -1,201 +0,0 @@ -# LeetCode 827. Making A Large Island's Solution -LeetCode link: [827. Making A Large Island](https://leetcode.com/problems/making-a-large-island/) - -## LeetCode problem description -You are given an `n x n` binary matrix `grid`. You are allowed to change at most one `0` to be `1`. - -Return the size of the largest island in `grid` after applying this operation. - -An island is a 4-directionally connected group of `1`s. - -### Example 1 -``` -Input: grid = [ - [1,0], - [0,1] -] -Output: 3 -Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3. -``` - -### Example 2 -``` -Input: grid = [ - [1,1], - [1,0] -] -Output: 4 -Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4. -``` -### Example 3 -``` -Input: grid = [ - [1,1], - [1,1] -] -Output: 4 -Explanation: Can't change any 0 to 1, only one island with area = 4. -``` - -### Constraints -- `n == grid.length` -- `n == grid[i].length` -- `1 <= n <= 500` -- `grid[i][j]` is either `0` or `1`. - -## Intuition -This problem is hard. Before solving this problem, you can do the following two problems first: - -- [200. Number of Islands](200-number-of-islands.md) -- [695. Max Area of Island](695-max-area-of-island.md) - -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -## Approach -1. Change one vertex from `0` to `1` to make the largest island means combining the adjacent islands of a `0` vertex. -1. We can mark an island's lands with one same id (`island_id`), and mark another island's lands with another `island_id`. To mark a land, just change its value to the `island_id`. -1. Use a `map` (or an `array`) to map each `island_id` to its `area`. -1. How to calculate the area of an island? Using `Depth-First Search` or `Breadth-First Search`. See [695. Max Area of Island](695-max-area-of-island.md). -1. Iterate through each `0` (water), then sum the `areas` of neighboring islands. -1. Record the max area and return it. - -## Complexity -* Time: `O(n * n)`. -* Space: `O(n * n)`. - -## Python -```python -from collections import defaultdict - -class Solution: - def __init__(self): - self.island_id = 2 - self.island_id_to_area = defaultdict(int) - - def largestIsland(self, grid: List[List[int]]) -> int: - self.grid = grid - max_area = 0 - - for i in range(len(grid)): - for j in range(len(grid[0])): - if self.grid[i][j] == 1: - self.depth_first_search(i, j) - self.island_id += 1 - - has_water = False - - for i in range(len(grid)): - for j in range(len(grid[0])): - if self.grid[i][j] == 0: - has_water = True - max_area = max(max_area, self.combined_islands_area(i, j)) - - if not has_water: - return len(grid) * len(grid[0]) - - return max_area - - def depth_first_search(self, i, j): - if i < 0 or j < 0 or i >= len(self.grid) or j >= len(self.grid[0]): - return - - if self.grid[i][j] != 1: - return - - self.grid[i][j] = self.island_id - self.island_id_to_area[self.island_id] += 1 - - for a, b in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0) - ]: - m = i + a - n = j + b - self.depth_first_search(m, n) - - def combined_islands_area(self, i, j): - island_ids = set() - - for a, b in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0) - ]: - m = i + a - n = j + b - - if m < 0 or n < 0 or m >= len(self.grid) or n >= len(self.grid[0]): - continue - - if self.grid[m][n] != 0: - island_ids.add(self.grid[m][n]) - - area = 1 - - for island_id in island_ids: - area += self.island_id_to_area[island_id] - - return area -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/833-find-and-replace-in-string.md b/en/1-1000/833-find-and-replace-in-string.md deleted file mode 100644 index 13b99ac..0000000 --- a/en/1-1000/833-find-and-replace-in-string.md +++ /dev/null @@ -1,113 +0,0 @@ -# 833. Find And Replace in String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [833. Find And Replace in String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/833-find-and-replace-in-string) for a better experience! - -LeetCode link: [833. Find And Replace in String](https://leetcode.com/problems/find-and-replace-in-string), difficulty: **Medium**. - -## LeetCode description of "833. Find And Replace in String" - -You are given a **0-indexed** string `s` that you must perform `k` replacement operations on. The replacement operations are given as three **0-indexed** parallel arrays, `indices`, `sources`, and `targets`, all of length `k`. - -To complete the *ith* replacement operation: - -1. Check if the **substring** `sources[i]` occurs at index `indices[i]` in the **original string** `s`. -2. If it does not occur, **do nothing**. -3. Otherwise if it does occur, **replace** that substring with `targets[i]`. - -For example, if `s = "abcd"`, `indices[i] = 0`, `sources[i] = "ab"`, and `targets[i] = "eee"`, then the result of this replacement will be `"eeecd"`. - - -All replacement operations must occur **simultaneously**, meaning the replacement operations should not affect the indexing of each other. The testcases will be generated such that the replacements will **not overlap**. - -- For example, a testcase with `s = "abc"`, `indices = [0, 1]`, and `sources = ["ab","bc"]` will not be generated because the `"ab"` and `"bc"` replacements overlap. -Return the ***resulting string*** after performing all replacement operations on `s`. - -A **substring** is a contiguous sequence of characters in a string. - -### [Example 1] - -![](../../images/examples/833_1.png) - -**Input**: `s = "abcd", indices = [0,2], sources = ["a","cd"], targets = ["eee","ffff"]` - -**Output**: `"eeebffff"` - -**Explanation**: - -

"a" occurs at index 0 in s, so we replace it with "eee".
-"cd" occurs at index 2 in s, so we replace it with "ffff".

- - -### [Example 2] - -![](../../images/examples/833_2.png) - -**Input**: `s = "abcd", indices = [0, 2], sources = ["ab","ec"], targets = ["eee","ffff"]` - -**Output**: `"eeecd"` - -**Explanation**: - -

"ab" occurs at index 0 in s, so we replace it with "eee".
-"ec" does not occur at index 2 in s, so we do nothing.

- - -### [Constraints] - -- `1 <= s.length <= 1000` -- `k == indices.length == sources.length == targets.length` -- `1 <= k <= 100` -- `0 <= indexes[i] < s.length` -- `1 <= sources[i].length, targets[i].length <= 50` -- `s` consists of only lowercase English letters. -- `sources[i]` and `targets[i]` consist of only lowercase English letters. - -## Intuition - -This question looks simple, but it takes a lot of time to do it. - -- Question 1: For the target string `result`, you can clone it based on the original string or build it from an empty string. Which one is better? -
Click to view the answer

Cloning based on the original string is better. Because you save a lot of substring assignment operations.

- -- Question 2: After replacing the substring of `result` with `targets[i]`, the length of `result` may change, which makes subsequent replacement difficult. How to solve it? -
Click to view the answer

Use technical means to keep the length of `result` unchanged after string replacement.

- -## Complexity - -> N = s.length - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def findReplaceString(self, s: str, indices: List[int], sources: List[str], targets: List[str]) -> str: - result = list(s) - - for i in range(len(indices)): - index = indices[i] - - if s[index:index + len(sources[i])] == sources[i]: - for j in range(index, index + len(sources[i])): - if j == index: - result[j] = targets[i] - else: - result[j] = '' - - return ''.join(result) -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [833. Find And Replace in String - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/833-find-and-replace-in-string). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1-1000/84-largest-rectangle-in-histogram.md b/en/1-1000/84-largest-rectangle-in-histogram.md deleted file mode 100644 index 4ca1951..0000000 --- a/en/1-1000/84-largest-rectangle-in-histogram.md +++ /dev/null @@ -1,297 +0,0 @@ -# 84. Largest Rectangle in Histogram (Monotonic Stack Solution) -LeetCode link: [84. Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) - -## LeetCode problem description -Given an array of integers `heights` representing the histogram's bar height where the width of each bar is `1`, return the area of the largest rectangle in the histogram. - -### Example 1 -![](../../images/examples/84_1.jpg) -``` -Input: heights = [2,1,5,6,2,3] -Output: 10 - -Explanation: The above is a histogram where width of each bar is 1. -The largest rectangle is shown in the red area, which has an area = 10 units. -``` - -### Example 2 -![](../../images/examples/84_2.jpg) -``` -Input: heights = [2,4] -Output: 4 -``` - -### Constraints -- `1 <= heights.length <= 100000` -- `0 <= heights[i] <= 10000` - -## Intuition -This problem can be solved using **Monotonic Stack**. - -* The `heights` in the stack from bottom to top are in ascending order. -* While `current_height < stack_top_height`, pop `stack_top_height`. -* Follow **Monotonic Stack**'s common rule: **only calculating when `pop()` is happening**. This common rule can be applied to calculating result for **most** of the `Monotonic Stack` problems. -* To calculate the `width`, there are two ways: - -### Way 1 -* The last `popped_index` from stack should be kept since we need it to calculate the `width`. - -### Way 2 -* Disappeared heights (popped when `current_height < stack_top_height`) are all taller than `stack_top_height`. This logic will be used to calculate the `width`. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Way 1 -```python -class Solution: - def largestRectangleArea(self, heights: List[int]) -> int: - max_area = 0 - index_stack = [] - heights.append(0) # different from way 2 - - for i, height in enumerate(heights): - popped_index = None # different from way 2 - - while index_stack and height < heights[index_stack[-1]]: - popped_index = index_stack.pop() - area = heights[popped_index] * (i - popped_index) # different from way 2 - max_area = max(max_area, area) - - if popped_index is not None: # different from way 2 - i = popped_index - heights[i] = height - - index_stack.append(i) - - return max_area -``` - -### Way 2 -```python -class Solution: - def largestRectangleArea(self, heights: List[int]) -> int: - max_area = 0 - index_stack = [] - heights = [0] + heights + [0] # different from way 1 - - for i, height in enumerate(heights): - while index_stack and height < heights[index_stack[-1]]: - popped_index = index_stack.pop() - - popped_height = heights[popped_index] - - left_index = index_stack[-1] # Different from way 1. popped_height's remaining left heights are all shorter than 'popped_height', because when 'popped_height' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - right_index = i # Different from way 1. popped_height's right heights (which are all taller than 'popped_height') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - width = right_index - left_index - 1 # Different from way 1. So in the range of 'width', they are all no shorter than `popped_height`, although they have been popped out of the stack (disappeared). - - area = popped_height * width - if area > max_area: - max_area = area - - index_stack.append(i) - - return max_area -``` - -## Java -```java -class Solution { - public int largestRectangleArea(int[] heightArray) { - var heights = new int[heightArray.length + 2]; - System.arraycopy(heightArray, 0, heights, 1, heightArray.length); - - var maxArea = 0; - var indexStack = new Stack(); - - for (var i = 0; i < heights.length; i++) { - while (!indexStack.empty() && heights[i] < heights[indexStack.peek()]) { - var poppedIndex = indexStack.pop(); - - var poppedHeight = heights[poppedIndex]; - var leftIndex = indexStack.peek(); // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - var rightIndex = i; // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - var width = rightIndex - leftIndex - 1; // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - var area = poppedHeight * width; - if (area > maxArea) { - maxArea = area; - } - } - - indexStack.push(i); - } - - return maxArea; - } -} -``` - -## C++ -```cpp -class Solution { -public: - int largestRectangleArea(vector heights) { - heights.insert(heights.begin(), 0); - heights.push_back(0); - auto max_area = 0; - stack index_stack; - - for (auto i = 0; i < heights.size(); i++) { - while (!index_stack.empty() && heights[i] < heights[index_stack.top()]) { - auto popped_height = heights[index_stack.top()]; - - index_stack.pop(); - - auto left_index = index_stack.top(); // popped_height's remaining left heights are all shorter than it, because when 'popped_height' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - auto right_index = i; // popped_height's right heights (which are all taller than 'popped_height') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - auto width = right_index - left_index - 1; // So in the range of 'width', they are all no shorter than `popped_height`, although they have been popped out of the stack (disappeared). - - auto area = popped_height * width; - if (area > max_area) { - max_area = area; - } - } - - index_stack.push(i); - } - - return max_area; - } -}; -``` - -## JavaScript -```javascript -var largestRectangleArea = function(heights) { - let maxArea = 0 - const indexStack = [] - heights = [0, ...heights, 0] - - heights.forEach((height, i) => { - while (indexStack.length > 0 && height < heights[indexStack.at(-1)]) { - const poppedIndex = indexStack.pop() - - const poppedHeight = heights[poppedIndex] - const leftIndex = indexStack.at(-1) // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - const rightIndex = i // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - const width = rightIndex - leftIndex - 1 // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - const area = poppedHeight * width - if (area > maxArea) { - maxArea = area - } - } - - indexStack.push(i) - }) - - return maxArea -}; -``` - -## C# -```c# -public class Solution -{ - public int LargestRectangleArea(int[] heights) - { - int maxArea = 0; - var indexStack = new Stack(); - heights = [0, ..heights, 0]; - - for (var i = 0; i < heights.Length; i++) - { - while (indexStack.Count > 0 && heights[i] < heights[indexStack.Peek()]) - { - int poppedIndex = indexStack.Pop(); - - int poppedHeight = heights[poppedIndex]; - int leftIndex = indexStack.Peek(); // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - int rightIndex = i; // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - int width = rightIndex - leftIndex - 1; // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - int area = poppedHeight * width; - if (area > maxArea) - { - maxArea = area; - } - } - - indexStack.Push(i); - } - - return maxArea; - } -} -``` - -## Go -```go -func largestRectangleArea(heightSlice []int) int { - maxArea := 0 - indexStack := []int{} - heights := append([]int{0}, append(heightSlice, 0)...) - - for i, height := range heights { - for len(indexStack) > 0 && height < heights[indexStack[len(indexStack) - 1]] { - poppedIndex := indexStack[len(indexStack) - 1] - indexStack = indexStack[:len(indexStack) - 1] - - poppedHeight := heights[poppedIndex] - leftIndex := indexStack[len(indexStack) - 1] // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - rightIndex := i // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - width := rightIndex - leftIndex - 1 // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - area := poppedHeight * width - if (area > maxArea) { - maxArea = area - } - } - - indexStack = append(indexStack, i) - } - - return maxArea -} -``` - -## Ruby -```ruby -def largest_rectangle_area(heights) - heights = [0] + heights + [0] - max_area = 0 - index_stack = [] - - heights.each_with_index do |height, i| - while !index_stack.empty? && height < heights[index_stack.last] - popped_index = index_stack.pop - - popped_height = heights[popped_index] - - left_index = index_stack[-1] # popped_height's remaining left heights are all shorter than 'popped_height', because when 'popped_height' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - right_index = i # popped_height's right heights (which are all taller than 'popped_height') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - width = right_index - left_index - 1 # So in the range of 'width', they are all no shorter than `popped_height`, although they have been popped out of the stack (disappeared). - - area = popped_height * width - max_area = area if area > max_area - end - - index_stack << i - end - - max_area -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1-1000/977-squares-of-a-sorted-array.md b/en/1-1000/977-squares-of-a-sorted-array.md deleted file mode 100644 index 0e91ae5..0000000 --- a/en/1-1000/977-squares-of-a-sorted-array.md +++ /dev/null @@ -1,354 +0,0 @@ -# 977. Squares of a Sorted Array - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [977. Squares of a Sorted Array - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/977-squares-of-a-sorted-array) for a better experience! - -LeetCode link: [977. Squares of a Sorted Array](https://leetcode.com/problems/squares-of-a-sorted-array), difficulty: **Easy**. - -## LeetCode description of "977. Squares of a Sorted Array" - -Given an integer array `nums` sorted in **non-decreasing** order, return *an array of* ***the squares of each number*** *sorted in non-decreasing order.* - -**Follow up**: Squaring each element and sorting the new array is very trivial, could you find an `O(n)` solution using a different approach? - -### [Example 1] - -**Input**: `nums = [-4,-1,0,3,10]` - -**Output**: `[0,1,9,16,100]` - -**Explanation**: - -

After squaring, the array becomes [16,1,0,9,100].
-After sorting, it becomes [0,1,9,16,100].

- - -### [Example 2] - -**Input**: `nums = [-7,-3,2,3,11]` - -**Output**: `[4,9,9,49,121]` - -### [Constraints] - -- `1 <= nums.length <= 10000` -- `10000 <= nums[i] <= 10000` -- `nums` is sorted in **non-decreasing** order. - -## Intuition 1 - -- The smallest number in the array is inside the array, and it needs to be traversed to find it, which is not very convenient. -- But if we think in reverse, can we prioritize other numbers more conveniently? So which numbers should be prioritized? - -
Click to view the answer

The answer is to prioritize the numbers at **both ends** of the array because they are the largest.

- -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public int[] sortedSquares(int[] nums) { - var results = new int[nums.length]; - var left = 0; - var right = nums.length - 1; - var index = right; - - while (left <= right) { - if (Math.abs(nums[left]) <= nums[right]) { - results[index] = nums[right] * nums[right]; - right -= 1; - } else { - results[index] = nums[left] * nums[left]; - left += 1; - } - - index -= 1; - } - - return results; - } -} -``` - -## Python - -```python -class Solution: - def sortedSquares(self, nums: List[int]) -> List[int]: - results = [None] * len(nums) - left = 0 - right = index = len(nums) - 1 - - while left <= right: - if abs(nums[left]) <= nums[right]: - results[index] = nums[right] ** 2 - right -= 1 - else: - results[index] = nums[left] ** 2 - left += 1 - - index -= 1 - - return results -``` - -## C++ - -```cpp -class Solution { -public: - vector sortedSquares(vector& nums) { - auto results = vector(nums.size()); - auto left = 0; - int right = nums.size() - 1; // Should not use 'auto' here because 'auto' will make this variable become `unsigned long` which has no `-1`. - auto index = right; - - while (left <= right) { - if (abs(nums[left]) <= nums[right]) { - results[index] = nums[right] * nums[right]; - right -= 1; - } else { - results[index] = nums[left] * nums[left]; - left += 1; - } - - index -= 1; - } - - return results; - } -}; -``` - -## JavaScript - -```javascript -var sortedSquares = function (nums) { - const results = Array(nums.length).fill(null) - let left = 0 - let right = nums.length - 1 - let index = right - - while (left <= right) { - if (Math.abs(nums[left]) <= nums[right]) { - results[index] = nums[right] * nums[right] - right -= 1 - } else { - results[index] = nums[left] * nums[left] - left += 1 - } - - index -= 1 - } - - return results -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] SortedSquares(int[] nums) - { - var results = new int[nums.Length]; - int left = 0; - int right = nums.Length - 1; - int index = right; - - while (left <= right) - { - if (Math.Abs(nums[left]) <= nums[right]) - { - results[index] = nums[right] * nums[right]; - right -= 1; - } - else - { - results[index] = nums[left] * nums[left]; - left += 1; - } - - index -= 1; - } - - return results; - } -} -``` - -## Go - -```go -func sortedSquares(nums []int) []int { - results := make([]int, len(nums)) - left := 0 - right := len(nums) - 1 - index := right - - for left <= right { - if math.Abs(float64(nums[left])) <= float64(nums[right]) { - results[index] = nums[right] * nums[right] - right -= 1 - } else { - results[index] = nums[left] * nums[left] - left += 1 - } - - index -= 1 - } - - return results -} -``` - -## Ruby - -```ruby -def sorted_squares(nums) - results = Array.new(nums.length) - left = 0 - right = nums.size - 1 - index = right - - while left <= right - if nums[left].abs <= nums[right] - results[index] = nums[right] * nums[right] - right -= 1 - else - results[index] = nums[left] * nums[left] - left += 1 - end - - index -= 1 - end - - results -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - - - -## Complexity - -- Time complexity: `O(N * log N)`. -- Space complexity: `O(N)`. - -## Java - -```java -class Solution { - public int[] sortedSquares(int[] nums) { - for (var i = 0; i < nums.length; i++) { - nums[i] *= nums[i]; - } - - Arrays.sort(nums); - - return nums; - } -} -``` - -## Python - -```python -class Solution: - def sortedSquares(self, nums: List[int]) -> List[int]: - results = [num ** 2 for num in nums] - - results.sort() - - return results -``` - -## C++ - -```cpp -class Solution { -public: - vector sortedSquares(vector& nums) { - for (auto i = 0; i < nums.size(); i++) { - nums[i] *= nums[i]; - } - - sort(nums.begin(), nums.end()); - - return nums; - } -}; -``` - -## JavaScript - -```javascript -var sortedSquares = function (nums) { - return _.sortBy( - nums.map((num) => num * num) - ) -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] SortedSquares(int[] nums) - { - for (int i = 0; i < nums.Length; i++) - nums[i] *= nums[i]; - - Array.Sort(nums); - - return nums; - } -} -``` - -## Go - -```go -func sortedSquares(nums []int) []int { - for i, _ := range nums { - nums[i] *= nums[i] - } - - sort.Sort(sort.IntSlice(nums)) - - return nums -} -``` - -## Ruby - -```ruby -def sorted_squares(nums) - nums.map { |num| num ** 2 }.sort -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [977. Squares of a Sorted Array - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/977-squares-of-a-sorted-array). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1001-2000/1035-uncrossed-lines.md b/en/1001-2000/1035-uncrossed-lines.md deleted file mode 100644 index caffe02..0000000 --- a/en/1001-2000/1035-uncrossed-lines.md +++ /dev/null @@ -1,221 +0,0 @@ -# 1035. Uncrossed Lines -LeetCode link: [1035. Uncrossed Lines](https://leetcode.com/problems/uncrossed-lines/) - -## LeetCode problem description -You are given two integer arrays `nums1` and `nums2`. We write the integers of `nums1` and `nums2` (in the order they are given) on two separate horizontal lines. - -We may draw connecting lines: a straight line connecting two numbers `nums1[i]` and `nums2[j]` such that: - -* `nums1[i]` == `nums2[j]`, and -* the line we draw does not intersect any other connecting (non-horizontal) line. - -Note that a connecting line cannot intersect even at the endpoints (i.e., each number can only belong to one connecting line). - -Return the maximum number of connecting lines we can draw in this way. - -``` -------------------------------------------------------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums1 = [1,4,2], nums2 = [1,2,4] -Output: 2 -Explanation: We can draw 2 uncrossed lines as in the diagram. -We cannot draw 3 uncrossed lines, because the line from nums1[1] = 4 to nums2[2] = 4 will intersect the line from nums1[2]=2 to nums2[1]=2. -------------------------------------------------------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2] -Output: 3 -------------------------------------------------------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1] -Output: 2 -------------------------------------------------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums1.length, nums2.length <= 500 -1 <= nums1[i], nums2[j] <= 2000 -------------------------------------------------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Python -```python -# Example of a 2D 'dp' array: -# nums1 = [ 2, 5, 1, 2, 5] -# nums2 = [10, 5, 2, 1, 5, 2] -# 10 5 2 1 5 2 -# 0 0 0 0 0 0 0 -# 2 0 0 0 1 1 1 1 -# 5 0 0 1 1 1 2 2 -# 1 0 ... -# 2 0 ... -# 5 0 ... -class Solution: - def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: - dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if nums1[i - 1] == nums2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - else: - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) - - return dp[-1][-1] -``` - -## Java -```java -class Solution { - public int maxUncrossedLines(int[] nums1, int[] nums2) { - var dp = new int[nums1.length + 1][nums2.length + 1]; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# -```c# -public class Solution -{ - public int MaxUncrossedLines(int[] nums1, int[] nums2) - { - var dp = new int[nums1.Length + 1, nums2.Length + 1]; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (nums1[i - 1] == nums2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1] + 1; - } - else - { - dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]); - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## C++ -```cpp -class Solution { -public: - int maxUncrossedLines(vector& nums1, vector& nums2) { - vector> dp(nums1.size() + 1, vector(nums2.size() + 1)); - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript -```javascript -var maxUncrossedLines = function(nums1, nums2) { - const dp = Array(nums1.length + 1).fill().map( - () => Array(nums2.length + 1).fill(0) - ) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] === nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go -```go -func maxUncrossedLines(nums1 []int, nums2 []int) int { - dp := make([][]int, len(nums1) + 1) - for i := range dp { - dp[i] = make([]int, len(nums2) + 1) - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if nums1[i - 1] == nums2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby -```ruby -def max_uncrossed_lines(nums1, nums2) - dp = Array.new(nums1.size + 1) do - Array.new(nums2.size + 1, 0) - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if nums1[i - 1] == nums2[j - 1] - dp[i - 1][j - 1] + 1 - else - [ dp[i][j - 1], dp[i - 1][j] ].max - end - end - end - - dp[-1][-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1049-last-stone-weight-ii.md b/en/1001-2000/1049-last-stone-weight-ii.md deleted file mode 100644 index 57c000c..0000000 --- a/en/1001-2000/1049-last-stone-weight-ii.md +++ /dev/null @@ -1,601 +0,0 @@ -# 1049. Last Stone Weight II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [1049. Last Stone Weight II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1049-last-stone-weight-ii) for a better experience! - -LeetCode link: [1049. Last Stone Weight II](https://leetcode.com/problems/last-stone-weight-ii), difficulty: **Medium**. - -## LeetCode description of "1049. Last Stone Weight II" - -You are given an array of integers `stones` where `stones[i]` is the weight of the `i-th` stone. - -We are playing a game with the stones. On each turn, we choose any two stones and smash them together. -Suppose the stones have weights `x` and `y` with `x <= y`. The result of this smash is: - -- If `x == y`, both stones are destroyed, and -- If `x != y`, the stone of weight `x` is destroyed, and the stone of weight `y` has new weight `y - x`. - -At the end of the game, there is **at most one** stone left. - -Return the smallest possible weight of the left stone. If there are no stones left, return `0`. - -### [Example 1] - -**Input**: `stones = [2,7,4,1,8,1]` - -**Output**: `1` - -**Explanation**: - -

We can combine 2 and 4 to get 2, so the array converts to [2,7,1,8,1] then,
-we can combine 7 and 8 to get 1, so the array converts to [2,1,1,1] then,
-we can combine 2 and 1 to get 1, so the array converts to [1,1,1] then,
-we can combine 1 and 1 to get 0, so the array converts to [1], then that's the optimal value.

- - -### [Example 2] - -**Input**: `stones = [31,26,33,21,40]` - -**Output**: `5` - -### [Constraints] - -1 <= stones.length <= 30 -1 <= stones[i] <= 100 - -### [Hints] - -
- Hint 1 - Think of the final answer as a sum of weights with + or - sign symbols in front of each weight. Actually, all sums with 1 of each sign symbol are possible. - - -
- -
- Hint 2 - Use dynamic programming: for every possible sum with N stones, those sums +x or -x is possible with N+1 stones, where x is the value of the newest stone. (This overcounts sums that are all positive or all negative, but those don't matter.) - - -
- -## Intuition 1 - -* This problem can be solved by brute force, that is, find all subsets of the array, see if the sum of each subset array is close to half of the sum of the complete array, and find the one that is closest. But when we see `stones.length <= 30`, we know that such a solution will definitely time out. -* So we need to change our thinking. The question is equivalent to finding the minimum difference between the sums of the two arrays after splitting. If we find a subset array whose sum is closest to half of the sum of the complete array, then it is the subset array we want. -* Then this problem will become a `0/1 Knapsack Problem`. - -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Pattern of "0/1 Knapsack Problem" - -The typical "0/1 knapsack problem" means that each "item" can only be used once to fill the "knapsack". "Items" have "weight" and "value" attributes. Find the maximum value of "items" that can be stored in the "knapsack". - -Its characteristics are: there is a **set of numbers**, each number can only be used once, and through some calculation, **another number** is obtained. The question can also be turned into whether it can be obtained? How many variations are there? And so on. - -Because "0/1 Knapsack Problem" belongs to "Dynamic Programming", I will explain it in the pattern of "Dynamic Programming". - -1. Determine what each value of the array `dp` represents. - - Prefer **one-dimensional rolling array** because the code is concise. - - Determine what is "item" and what is "knapsack". - - If `dp[j]` is a boolean value, then `dp[j]` indicates whether the `sum` of the first `i` items can get `j`. - - If `dp[j]` is a numerical value, then `dp[j]` indicates the maximum (or minimum) value that `dp[j]` can reach using the first `i` items. - -2. Initialize the value of the array `dp`. - - Determine the size of the "knapsack". It is necessary to add 1 to the size of the knapsack, that is, insert `dp[0]` as the starting point, which is convenient for understanding and reference. - - `dp[0]` sometimes needs special treatment. -3. According to an example, fill in the `dp` grid data "in order". - - First in the outer loop, **traverse the items**. - - Then in the inner loop, **traverse the knapsack size**. - - When traversing the knapsack size, since `dp[j]` depends on `dp[j]` and `dp[j - weights[i]]`, we should traverse the `dp` array **from right to left**. - - Please think about whether it is possible to traverse the `dp` array from `left to right`? -4. According to the `dp` grid data, derive the "recursive formula". - - If `dp[j]` is a boolean value: - - ```cpp - dp[j] = dp[j] || dp[j - items[i]] - ``` - - If `dp[j]` is a numeric value: - - ```cpp - dp[j] = min_or_max(dp[j], dp[j - weights[i]] + values[i]) - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Step by Step Solutions - -1. Determine the **meaning** of the `dp[j]` - - `dp[j]` represents whether it is possible to `sum` the first `i` `stones` to get `j`. - - `dp[j]` is a boolean. -2. Determine the `dp` array's initial value - - Use an example: - - ``` - stones = [2,7,4,1,8,1], so 'half of the sum' is 11. - The `size` of the knapsack is `11 + 1`, and the `items` are `stones`. - So after initialization, the 'dp' array would be: - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F # dp - # 2 - # 7 - # 4 - # 1 - # 8 - # 1 - ``` - - `dp[0]` is set to `true`, indicating that an empty knapsack can be achieved by not using any `stones`. In addition, it is used as the starting value, and the subsequent `dp[j]` will depend on it. If it is `false`, all values of `dp[j]` will be `false`. - - `dp[j] = false (j != 0)`, indicating that it is impossible to get `j` with no `stones`. -3. Fill in the `dp` grid data "in order" according to an example. - - ``` - 1. Use the first stone '2'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 2 T F T F F F F F F F F F # dp - ``` - ``` - 2. Use the second stone '7'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 2 T F T F F F F F F F F F - # 7 T F T F F F F T F T F F - ``` - ``` - 3. Use the third stone '4'. - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 2 T F T F F F F F F F F F - # 7 T F T F F F F F T F F F - # 4 T F T F T F T T F T F T # dp - # ... - ``` -4. Based on the `dp` grid data, derive the "recursive formula". - - ```cpp - dp[j] = dp[j] || dp[j - stones[i]] - ``` -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -## Complexity - -- Time complexity: `O(n * sum/2)`. -- Space complexity: `O(sum/2)`. - -## Python - -```python -class Solution: - def lastStoneWeightII(self, stones: List[int]) -> int: - sum_ = sum(stones) - - dp = [False] * (sum_ // 2 + 1) - dp[0] = True - - for stone in stones: - # If not traversing in reverse order, the newly assigned value `dp[j]` will act as `dp[j - stone]` later, - # then the subsequent `dp[j]` will be affected. But each `stone` can only be used once! - for j in range(len(dp) - 1, 0, -1): - if j < stone: - break - dp[j] = dp[j] or dp[j - stone] - - for i in range(len(dp) - 1, -1, -1): - if dp[i]: - return sum_ - i * 2 -``` - -## C# - -```csharp -public class Solution { - public int LastStoneWeightII(int[] stones) { - var sum = stones.Sum(); - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (int stone in stones) { - for (var j = dp.GetUpperBound(0); j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone]; - } - } - - for (var j = dp.GetUpperBound(0); j >= 0; j--) { - if (dp[j]) { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - int lastStoneWeightII(vector& stones) { - auto sum = reduce(stones.begin(), stones.end()); - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto stone : stones) { - for (auto j = dp.size() - 1; j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone]; - } - } - - for (auto i = dp.size() - 1; i >= 0; i--) { - if (dp[i]) { - return sum - i * 2; - } - } - - throw logic_error("lastStoneWeightII() has a logical error!"); - } -}; -``` - -## Java - -```java -class Solution { - public int lastStoneWeightII(int[] stones) { - var sum = IntStream.of(stones).sum(); - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var stone : stones) { - for (var j = dp.length - 1; j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone]; - } - } - - for (var j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## JavaScript - -```javascript -var lastStoneWeightII = function (stones) { - const sum = _.sum(stones) - - const dp = Array(Math.floor(sum / 2) + 1).fill(false) - dp[0] = true - - for (const stone of stones) { - for (let j = dp.length - 1; j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone] - } - } - - for (let j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2 - } - } -}; -``` - -## Go - -```go -func lastStoneWeightII(stones []int) int { - sum := 0 - for _, stone := range stones { - sum += stone - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, stone := range stones { - for j := len(dp) - 1; j >= stone; j-- { - dp[j] = dp[j] || dp[j - stone] - } - } - - for j := len(dp) - 1; j >= 0; j-- { - if dp[j] { - return sum - j * 2 - } - } - - return -1 // This line should be unreachable. It represents function has a logical error. -} -``` - -## Ruby - -```ruby -def last_stone_weight_ii(stones) - sum = stones.sum - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - stones.each do |stone| - (1...dp.size).reverse_each do |j| - break if j < stone - - dp[j] = dp[j] || dp[j - stone] - end - end - - (0...dp.size).reverse_each do |j| - return sum - j * 2 if dp[j] - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Intuition 2 - -In solution 1, the traversal order is **from right to left** which really matters. - -During the interview, you need to remember it. Is there any way to not worry about the traversal order? - -
Click to view the answer

As long as you copy the original `dp` and reference the value of the copy, you don't have to worry about the original `dp` value being modified.

- -## Complexity - -- Time complexity: `O(n * sum/2)`. -- Space complexity: `O(n * sum/2)`. - -## Python - -```python -class Solution: - def lastStoneWeightII(self, stones: List[int]) -> int: - sum_ = sum(stones) - - dp = [False] * (sum_ // 2 + 1) - dp[0] = True - - for stone in stones: - dc = dp.copy() - - for j in range(stone, len(dp)): - dp[j] = dc[j] or dc[j - stone] - - for i in range(len(dp) - 1, -1, -1): - if dp[i]: - return sum_ - i * 2 -``` - -## C# - -```csharp -public class Solution -{ - public int LastStoneWeightII(int[] stones) - { - int sum = stones.Sum(); - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (int stone in stones) - { - var dc = (bool[]) dp.Clone(); - - for (var j = stone; j < dp.Length; j++) - { - dp[j] = dc[j] || dc[j - stone]; - } - } - - for (var j = dp.GetUpperBound(0); j >= 0; j--) - { - if (dp[j]) - { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - int lastStoneWeightII(vector& stones) { - auto sum = reduce(stones.begin(), stones.end()); - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto stone : stones) { - auto dc = dp; - - for (auto j = stone; j < dp.size(); j++) { - dp[j] = dc[j] || dc[j - stone]; - } - } - - for (auto i = dp.size() - 1; i >= 0; i--) { - if (dp[i]) { - return sum - i * 2; - } - } - - throw logic_error("lastStoneWeightII() has a logical error!"); - } -}; -``` - -## Java - -```java -class Solution { - public int lastStoneWeightII(int[] stones) { - var sum = IntStream.of(stones).sum(); - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var stone : stones) { - var dc = dp.clone(); - - for (var j = stone; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - stone]; - } - } - - for (var j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## JavaScript - -```javascript -var lastStoneWeightII = function (stones) { - const sum = _.sum(stones) - - const dp = Array(Math.floor(sum / 2) + 1).fill(false) - dp[0] = true - - for (const stone of stones) { - const dc = [...dp] - - for (let j = stone; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - stone] - } - } - - for (let j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2 - } - } -}; -``` - -## Go - -```go -func lastStoneWeightII(stones []int) int { - sum := 0 - for _, stone := range stones { - sum += stone - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, stone := range stones { - dc := slices.Clone(dp) - - for j := stone; j < len(dp); j++ { - dp[j] = dc[j] || dc[j - stone] - } - } - - for j := len(dp) - 1; j >= 0; j-- { - if dp[j] { - return sum - j * 2 - } - } - - return -1 // This line should be unreachable. It represents function has a logical error. -} -``` - -## Ruby - -```ruby -def last_stone_weight_ii(stones) - sum = stones.sum - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - stones.each do |stone| - dc = dp.clone - - (stone...dp.size).each do |j| - dp[j] = dc[j] || dc[j - stone] - end - end - - (0...dp.size).reverse_each do |j| - return sum - j * 2 if dp[j] - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [1049. Last Stone Weight II - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1049-last-stone-weight-ii). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1001-2000/1071-greatest-common-divisor-of-strings.md b/en/1001-2000/1071-greatest-common-divisor-of-strings.md deleted file mode 100644 index f961de0..0000000 --- a/en/1001-2000/1071-greatest-common-divisor-of-strings.md +++ /dev/null @@ -1,264 +0,0 @@ -# 1071. Greatest Common Divisor of Strings - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [1071. Greatest Common Divisor of Strings - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1071-greatest-common-divisor-of-strings) for a better experience! - -LeetCode link: [1071. Greatest Common Divisor of Strings](https://leetcode.com/problems/greatest-common-divisor-of-strings), difficulty: **Easy**. - -## LeetCode description of "1071. Greatest Common Divisor of Strings" - -For two strings `s` and `t`, we say "`t` divides `s`" if and only if `s = t + t + t + ... + t + t` (i.e., `t` is concatenated with itself one or more times). - -Given two strings `str1` and `str2`, return the **largest string** `x` such that `x` divides both `str1` and `str2`. - -### [Example 1] - -**Input**: `str1 = "ABCABC", str2 = "ABC"` - -**Output**: `"ABC"` - -### [Example 2] - -**Input**: `str1 = "ABABAB", str2 = "ABAB"` - -**Output**: `"AB"` - -### [Example 3] - -**Input**: `str1 = "LEET", str2 = "CODE"` - -**Output**: `""` - -### [Constraints] - -- `1 <= str1.length, str2.length <= 1000` -- `str1` and `str2` consist of English uppercase letters. - -### [Hints] - -
- Hint 1 - The greatest common divisor must be a prefix of each string, so we can try all prefixes. - - -
- -## Intuition - -The greatest common divisor must be a prefix of each string, so we can try all prefixes. - -Enumerate all possible prefixes and check whether repeating the prefix several times can form the original strings. - -Return the longest one that satisfies the condition. - - -## Step by Step Solutions - -1. Get the minimum length `min_size` of the two strings. -2. For length `i` from `1` to `min_size`, enumerate the prefix `candidate`. -3. If the length of `candidate` can divide both `str1` and `str2`, and repeating `candidate` the corresponding times equals `str1` and `str2`, update the result. -4. Finally, return the longest valid `candidate`. - -## Complexity - -- Time complexity: `O(N * (N + M))`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def gcdOfStrings(self, str1: str, str2: str) -> str: - result = "" - min_size = min(len(str1), len(str2)) - - for i in range(1, min_size + 1): - if len(str1) % i == 0 and len(str2) % i == 0: - candidate = str1[:i] - - if candidate * (len(str1) // i) == str1 and candidate * (len(str2) // i) == str2: - result = candidate - - return result -``` - -## Java - -```java -class Solution { - public String gcdOfStrings(String str1, String str2) { - String result = ""; - int minSize = Math.min(str1.length(), str2.length()); - - for (int i = 1; i <= minSize; i++) { - if (str1.length() % i == 0 && str2.length() % i == 0) { - String candidate = str1.substring(0, i); - if (isValid(candidate, str1) && isValid(candidate, str2)) { - result = candidate; - } - } - } - - return result; - } - - private boolean isValid(String candidate, String s) { - int count = s.length() / candidate.length(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < count; i++) { - sb.append(candidate); - } - return sb.toString().equals(s); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string gcdOfStrings(string str1, string str2) { - string result; - int min_size = min(str1.size(), str2.size()); - - for (int i = 1; i <= min_size; i++) { - if (str1.size() % i == 0 && str2.size() % i == 0) { - string candidate = str1.substr(0, i); - if (isValid(candidate, str1) && isValid(candidate, str2)) { - result = candidate; - } - } - } - - return result; - } - -private: - bool isValid(const string& candidate, const string& s) { - int count = s.size() / candidate.size(); - string temp; - for (int i = 0; i < count; i++) { - temp += candidate; - } - return temp == s; - } -}; -``` - -## C# - -```csharp -public class Solution -{ - public string GcdOfStrings(string str1, string str2) - { - string result = ""; - int minSize = Math.Min(str1.Length, str2.Length); - - for (int i = 1; i <= minSize; i++) - { - if (str1.Length % i == 0 && str2.Length % i == 0) - { - string candidate = str1.Substring(0, i); - if (IsValid(candidate, str1) && IsValid(candidate, str2)) - { - result = candidate; - } - } - } - - return result; - } - - private bool IsValid(string candidate, string s) - { - return string.Concat(Enumerable.Repeat(candidate, s.Length / candidate.Length)) == s; - } -} -``` - -## JavaScript - -```javascript -var gcdOfStrings = function (str1, str2) { - let result = ""; - const minSize = Math.min(str1.length, str2.length); - - const isValid = (candidate, s) => { - return candidate.repeat(s.length / candidate.length) === s; - }; - - for (let i = 1; i <= minSize; i++) { - if (str1.length % i === 0 && str2.length % i === 0) { - const candidate = str1.substring(0, i); - if (isValid(candidate, str1) && isValid(candidate, str2)) { - result = candidate; - } - } - } - - return result; -} - -``` - -## Go - -```go -func gcdOfStrings(str1 string, str2 string) string { - result := "" - minSize := len(str1) - if len(str2) < minSize { - minSize = len(str2) - } - - for i := 1; i <= minSize; i++ { - if len(str1) % i == 0 && len(str2) % i == 0 { - candidate := str1[:i] - if isValid(candidate, str1) && isValid(candidate, str2) { - result = candidate - } - } - } - - return result -} - -func isValid(candidate, s string) bool { - return strings.Repeat(candidate, len(s)/len(candidate)) == s -} -``` - -## Ruby - -```ruby -def gcd_of_strings(str1, str2) - result = "" - min_size = [ str1.size, str2.size ].min - - (1..min_size).each do |i| - next unless (str1.size % i).zero? && (str2.size % i).zero? - - candidate = str1[0...i] - next unless candidate * (str1.size / i) == str1 - next unless candidate * (str2.size / i) == str2 - - result = candidate - end - - result -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [1071. Greatest Common Divisor of Strings - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1071-greatest-common-divisor-of-strings). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1001-2000/1143-longest-common-subsequence.md b/en/1001-2000/1143-longest-common-subsequence.md deleted file mode 100644 index 0585fc1..0000000 --- a/en/1001-2000/1143-longest-common-subsequence.md +++ /dev/null @@ -1,227 +0,0 @@ -# 1143. Longest Common Subsequence -LeetCode link: [1143. Longest Common Subsequence](https://leetcode.com/problems/longest-common-subsequence/) - -## LeetCode problem description -Given two strings `text1` and `text2`, return the length of their longest **common subsequence**. If there is no common subsequence, return `0`. - -A `subsequence` of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters. - -* For example, `"ace"` is a subsequence of `"abcde"`. - -A **common subsequence** of two strings is a subsequence that is common to both strings. - -``` ----------------------------------------------------------------------------- -[Example 1] - -Input: text1 = "abcde", text2 = "ace" -Output: 3 -Explanation: The longest common subsequence is "ace" and its length is 3. ----------------------------------------------------------------------------- -[Example 2] - -Input: text1 = "abc", text2 = "abc" -Output: 3 -Explanation: The longest common subsequence is "abc" and its length is 3. ----------------------------------------------------------------------------- -[Example 3] - -Input: text1 = "abc", text2 = "def" -Output: 0 -Explanation: There is no such common subsequence, so the result is 0. ----------------------------------------------------------------------------- -[Constraints] - -1 <= text1.length, text2.length <= 1000 -text1 and text2 consist of only lowercase English characters. ----------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Java -```java -// Example of a 2D 'dp' array: -// a c e -// 0 0 0 0 -// a 0 1 1 1 -// b 0 1 1 1 -// c 0 1 2 2 -// d 0 1 2 2 -// e 0 1 2 3 -class Solution { - public int longestCommonSubsequence(String text1, String text2) { - var dp = new int[text1.length() + 1][text2.length() + 1]; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (text1.charAt(i - 1) == text2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# -```c# -public class Solution -{ - public int LongestCommonSubsequence(string text1, string text2) - { - var dp = new int[text1.Length + 1, text2.Length + 1]; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (text1[i - 1] == text2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1] + 1; - } - else - { - dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]); - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Python -```python -# Example of a 2D 'dp' array: -# a b f k m a j b -# 0 0 0 0 0 0 0 0 0 -# a 0 1 1 1 1 1 1 1 1 -# j 0 1 1 1 1 1 1 2 2 -# f 0 1 1 2 2 2 2 2 2 -# b 0 1 2 2 2 2 2 2 2 -# m 0 1 2 2 2 3 3 3 3 -# k 0 1 2 2 2 3 3 3 3 -# j 0 1 2 2 2 3 3 4 4 -class Solution: - def longestCommonSubsequence(self, text1: str, text2: str) -> int: - dp = [[0] * (len(text2) + 1) for _ in range(len(text1) + 1)] - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if text1[i - 1] == text2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - else: - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) - - return dp[-1][-1] -``` - -## C++ -```cpp -class Solution { -public: - int longestCommonSubsequence(string text1, string text2) { - vector> dp(text1.size() + 1, vector(text2.size() + 1)); - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (text1[i - 1] == text2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript -```javascript -var longestCommonSubsequence = function (text1, text2) { - const dp = Array(text1.length + 1).fill().map( - () => Array(text2.length + 1).fill(0) - ) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (text1[i - 1] === text2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go -```go -func longestCommonSubsequence(text1 string, text2 string) int { - dp := make([][]int, len(text1) + 1) - for i := range dp { - dp[i] = make([]int, len(text2) + 1) - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if text1[i - 1] == text2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby -```ruby -def longest_common_subsequence(text1, text2) - dp = Array.new(text1.size + 1) do - Array.new(text2.size + 1, 0) - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if text1[i - 1] == text2[j - 1] - dp[i - 1][j - 1] + 1 - else - [ dp[i][j - 1], dp[i - 1][j] ].max - end - end - end - - dp[-1][-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md b/en/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md deleted file mode 100644 index 2087b35..0000000 --- a/en/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md +++ /dev/null @@ -1,146 +0,0 @@ -# 1334. Find the City With the Smallest Number of Neighbors at a Threshold Distance - Best Practices of LeetCode Solutions -LeetCode link: [1334. Find the City With the Smallest Number of Neighbors at a Threshold Distance](https://leetcode.com/problems/find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance), difficulty: **Medium**. - -## LeetCode description of "1334. Find the City With the Smallest Number of Neighbors at a Threshold Distance" -There are `n` cities numbered from `0` to `n-1`. Given the array edges where `edges[i] = [from_i, to_i, weight_i]` represents a bidirectional and weighted edge between cities `from_i` and `to_i`, and given the integer `distanceThreshold`. - -Return the city with the smallest number of cities that are reachable through some path and whose distance is **at most** `distanceThreshold`, If there are multiple such cities, return the city with the greatest number. - -Notice that the distance of a path connecting cities _**i**_ and _**j**_ is equal to the sum of the edges' weights along that path. - -### [Example 1] -![](../../images/examples/1334_1.png) - -**Input**: `n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4` - -**Output**: `3` - -**Explanation**: -``` -The figure above describes the graph. -The neighboring cities at a distanceThreshold = 4 for each city are: -City 0 -> [City 1, City 2] -City 1 -> [City 0, City 2, City 3] -City 2 -> [City 0, City 1, City 3] -City 3 -> [City 1, City 2] -Cities 0 and 3 have 2 neighboring cities at a distanceThreshold = 4, but we have to return city 3 since it has the greatest number. -``` - -### [Example 2] -![](../../images/examples/1334_2.png) - -**Input**: `n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2` - -**Output**: `0` - -**Explanation**: -``` -The figure above describes the graph. -The neighboring cities at a distanceThreshold = 2 for each city are: -City 0 -> [City 1] -City 1 -> [City 0, City 4] -City 2 -> [City 3, City 4] -City 3 -> [City 2, City 4] -City 4 -> [City 1, City 2, City 3] -The city 0 has 1 neighboring city at a distanceThreshold = 2. -``` - -### [Constraints] -- `2 <= n <= 100` -- `1 <= edges.length <= n * (n - 1) / 2` -- `edges[i].length == 3` -- `0 <= from_i < to_i < n` -- `1 <= weight_i, distanceThreshold <= 10^4` -- All pairs `(from_i, to_i)` are distinct. - -### [Hints] -
- Hint 1 - Use Floyd-Warshall's algorithm to compute any-point to any-point distances. (Or can also do Dijkstra from every node due to the weights are non-negative). -
- -
- Hint 2 - For each city calculate the number of reachable cities within the threshold, then search for the optimal city. -
- -## Intuition -Just like the `Hints` says, you can use **Floyd-Warshall Algorithm** to compute any-point to any-point shortest distances. - -Or you can also do **Dijkstra Algorithm** from every node due to the weights are non-negative. - -Or you can also do **Queue-Improved Bellman-Ford Algorithm** from every node. - -## Complexity -* Time: `O(N^3)`. -* Space: `O(N^2)`. - -## Python -```python -class Solution: - def findTheCity(self, n: int, edges: List[List[int]], distance_threshold: int) -> int: - dp = [] - - for i in range(n): - dp.append([float('inf')] * n) - dp[i][i] = 0 - - for i, j, weight in edges: - dp[i][j] = weight - dp[j][i] = weight - - for k in range(n): - for i in range(n): - for j in range(n): - dp[i][j] = min( - dp[i][j], - dp[i][k] + dp[k][j], - ) - - result = -1 - min_count = float('inf') - - for i, row in enumerate(dp): - count = len([distance for distance in row if distance <= distance_threshold]) - - if count <= min_count: - min_count = count - result = i - - return result -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1431-kids-with-the-greatest-number-of-candies.md b/en/1001-2000/1431-kids-with-the-greatest-number-of-candies.md deleted file mode 100644 index a1f2a66..0000000 --- a/en/1001-2000/1431-kids-with-the-greatest-number-of-candies.md +++ /dev/null @@ -1,192 +0,0 @@ -# 1431. Kids With the Greatest Number of Candies - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [1431. Kids With the Greatest Number of Candies - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1431-kids-with-the-greatest-number-of-candies) for a better experience! - -LeetCode link: [1431. Kids With the Greatest Number of Candies](https://leetcode.com/problems/kids-with-the-greatest-number-of-candies), difficulty: **Easy**. - -## LeetCode description of "1431. Kids With the Greatest Number of Candies" - -There are `n` kids with candies. You are given an integer array `candies`, where each `candies[i]` represents the number of candies the `i-th` kid has, and an integer `extraCandies`, denoting the number of extra candies that you have. - -Return a boolean array resu`lt of length `n`, where `result[i]` is `true` if, after giving the `i-th` kid all the `extraCandies`, they will have the **greatest** number of candies among all the kids, or `false` otherwise. - -Note that **multiple** kids can have the **greatest** number of candies. - -### [Example 1] - -**Input**: `candies = [2,3,5,1,3], extraCandies = 3` - -**Output**: `[true,true,true,false,true]` - -**Explanation**: - -

If you give all extraCandies to:
-- Kid 1, they will have 2 + 3 = 5 candies, which is the greatest among the kids.
-- Kid 2, they will have 3 + 3 = 6 candies, which is the greatest among the kids.
-- Kid 3, they will have 5 + 3 = 8 candies, which is the greatest among the kids.
-- Kid 4, they will have 1 + 3 = 4 candies, which is not the greatest among the kids.
-- Kid 5, they will have 3 + 3 = 6 candies, which is the greatest among the kids.

- - -### [Example 2] - -**Input**: `candies = [4,2,1,1,2], extraCandies = 1` - -**Output**: `[true,false,false,false,false]` - -**Explanation**: - -

There is only 1 extra candy.
-Kid 1 will always have the greatest number of candies, even if a different kid is given the extra candy.

- - -### [Example 3] - -**Input**: `candies = [12,1,12], extraCandies = 10` - -**Output**: `[true,false,true]` - -### [Constraints] - -- `n == candies.length` -- `2 <= n <= 100` -- `1 <= candies[i] <= 100` -- `1 <= extraCandies <= 50` - -### [Hints] - -
- Hint 1 - For each kid check if candies[i] + extraCandies ≥ maximum in Candies[i]. - - -
- -## Intuition - -1. Find the maximum number of candies among all kids -2. Check if each kid can reach or exceed this maximum after receiving extra candies - -## Step by Step Solutions - -1. `max_candy = candies.max` → Directly get the maximum value from the array -2. `candies.map { |c| c + extra_candy >= max_candy }` → Use `map` to iterate and check if each kid can have the most candies - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def kidsWithCandies(self, candies: List[int], extra_candy: int) -> List[bool]: - max_candy = max(candies) - result = [] - - for candy in candies: - result.append(candy + extra_candy >= max_candy) - - return result -``` - -## Java - -```java -class Solution { - public List kidsWithCandies(int[] candies, int extraCandy) { - int maxCandy = Arrays.stream(candies).max().getAsInt(); - List result = new ArrayList<>(); - - for (int candy : candies) { - result.add(candy + extraCandy >= maxCandy); - } - - return result; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector kidsWithCandies(vector& candies, int extraCandy) { - int max_candy = *max_element(candies.begin(), candies.end()); - vector result; - - for (int candy : candies) { - result.push_back(candy + extraCandy >= max_candy); - } - - return result; - } -}; -``` - -## JavaScript - -```javascript -var kidsWithCandies = function(candies, extraCandy) { - const maxCandy = Math.max(...candies) - return candies.map((candy) => candy + extraCandy >= maxCandy) -}; - -``` - -## Go - -```go -func kidsWithCandies(candies []int, extraCandy int) []bool { - maxCandy := candies[0] - for _, candy := range candies { - if candy > maxCandy { - maxCandy = candy - } - } - - result := make([]bool, len(candies)) - for i, candy := range candies { - result[i] = candy+extraCandy >= maxCandy - } - - return result -} -``` - -## C# - -```csharp -public class Solution -{ - public IList KidsWithCandies(int[] candies, int extraCandy) - { - int maxCandy = candies.Max(); - return candies.Select(candy => candy + extraCandy >= maxCandy).ToList(); - } -} -``` - -## Ruby - -```ruby -def kids_with_candies(candies, extra_candy) - max_candy = candies.max - candies.map { |candy| candy + extra_candy >= max_candy } -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [1431. Kids With the Greatest Number of Candies - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1431-kids-with-the-greatest-number-of-candies). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1001-2000/1514-path-with-maximum-probability.md b/en/1001-2000/1514-path-with-maximum-probability.md deleted file mode 100644 index 19ee671..0000000 --- a/en/1001-2000/1514-path-with-maximum-probability.md +++ /dev/null @@ -1,231 +0,0 @@ -# 1514. Path with Maximum Probability - Best Practices of LeetCode Solutions -LeetCode link: [1514. Path with Maximum Probability](https://leetcode.com/problems/path-with-maximum-probability), difficulty: **Medium**. - -## LeetCode description of "1514. Path with Maximum Probability" -You are given an undirected weighted graph of `n` nodes (0-indexed), represented by an edge list where `edges[i] = [a, b]` is an undirected edge connecting the nodes `a` and `b` with a probability of success of traversing that edge `succProb[i]`. - -Given two nodes `start` and `end`, find the path with the maximum probability of success to go from `start` to `end` and return its success probability. - -If there is no path from `start` to `end`, return 0. Your answer will be accepted if it differs from the correct answer by at most **1e-5**. - -### [Example 1] -![](../../images/examples/1514_1.png) - -**Input**: `n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2` - -**Output**: `0.25000` - -**Explanation**: `There are two paths from start to end, one having a probability of success = 0.2 and the other has 0.5 * 0.5 = 0.25.` - -### [Example 2] -![](../../images/examples/1514_2.png) - -**Input**: `n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2` - -**Output**: `0.30000` - -### [Example 3] -![](../../images/examples/1514_3.png) - -**Input**: `n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2` - -**Output**: `0.00000` - -**Explanation**: `There is no path between 0 and 2.` - -### [Constraints] -- `2 <= n <= 10^4` -- `0 <= start, end < n` -- `start != end` -- `0 <= a, b < n` -- `a != b` -- `0 <= succProb.length == edges.length <= 2*10^4` -- `0 <= succProb[i] <= 1` -- There is at most one edge between every two nodes. - -### [Hints] -
- Hint 1 - Multiplying probabilities will result in precision errors. -
- -
- Hint 2 - Take log probabilities to sum up numbers instead of multiplying them. -
- -
- Hint 3 - Use Dijkstra's algorithm to find the minimum path between the two nodes after negating all costs. -
- -## Intuition -We can use **Dijkstra's algorithm**. - -![](../../images/graph_Dijkstra_algorithm_animation.gif) - -This animation is about **Dijkstra's algorithm** to find the shortest path between `a` and `b`. -It picks the unvisited vertex with the lowest distance, calculates the distance through it to each unvisited neighbor, and updates the neighbor's distance if smaller. Mark **visited** (set to red) when done with neighbors. - -In short, **Dijkstra's algorithm** means **to find the nearest point and walk through it, and never go back. Repeatedly**. - -## Complexity -**V**: vertex count, **E**: Edge count. - -### Dijkstra's algorithm without using `heap sort` -* Time: `O(V * V)`. -* Space: `O(V + E)`. - -### Dijkstra's algorithm using `heap sort` -* Time: `O(E * log(E))`. -* Space: `O(V + E)`. - -## Python -### Dijkstra's algorithm without using `heap sort` -The code will time out when executed on LeetCode, but this is not a problem with the code itself. The `heap sort` implementation below will not time out. -```python -class Solution: - def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float: - node_to_pairs = defaultdict(set) - - for i, (source_node, target_node) in enumerate(edges): - node_to_pairs[source_node].add((target_node, succ_prob[i])) - node_to_pairs[target_node].add((source_node, succ_prob[i])) - - max_probabilities = [0] * n - max_probabilities[start_node] = 1 - visited = [False] * n - - for _ in range(n - 1): - current_node = None - maximum_probability = 0 - - for node, probability in enumerate(max_probabilities): - if not visited[node] and probability > maximum_probability: - maximum_probability = probability - current_node = node - - if current_node is None: - break - - visited[current_node] = True - - for target_node, probability in node_to_pairs[current_node]: - probability_ = probability * max_probabilities[current_node] - - if probability_ > max_probabilities[target_node]: - max_probabilities[target_node] = probability_ - - return max_probabilities[end_node] -``` - -### Dijkstra's algorithm using `heap sort` -#### 1. `heap sort` without using `visited` -```python -import heapq - -class Solution: - def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float: - node_to_pairs = defaultdict(set) - - for i, (source_node, target_node) in enumerate(edges): - node_to_pairs[source_node].add((target_node, succ_prob[i])) - node_to_pairs[target_node].add((source_node, succ_prob[i])) - - max_probabilities = [0 for node in range(n)] - max_probabilities[start_node] = 1 - priority_queue = [(-1, start_node)] - - while priority_queue: - current_probability, current_node = heapq.heappop(priority_queue) - - if current_node == end_node: - return -current_probability - - for target_node, probability in node_to_pairs[current_node]: - probability_ = abs(current_probability) * probability - - if probability_ > max_probabilities[target_node]: - max_probabilities[target_node] = probability_ - # It may cause the same `target_node` added into `priority_queue` more than once, but it doesn't matter. Because only the one `heappush`ed first may change the `max_probabilities` data. - heapq.heappush(priority_queue, (-probability_, target_node)) - - return 0 -``` - -#### 2. `heap sort` using `visited` -```python -import heapq - -class Solution: - def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float: - node_to_pairs = defaultdict(set) - - for i, (source_node, target_node) in enumerate(edges): - node_to_pairs[source_node].add((target_node, succ_prob[i])) - node_to_pairs[target_node].add((source_node, succ_prob[i])) - - max_probabilities = [0 for node in range(n)] - max_probabilities[start_node] = 1 - priority_queue = [(-1, start_node)] - visited = [False] * n # added 1 - - while priority_queue: - current_probability, current_node = heapq.heappop(priority_queue) - - if current_node == end_node: - return -current_probability - - if visited[current_node]: # added 3 - continue - - visited[current_node] = True # added 2 - - for target_node, probability in node_to_pairs[current_node]: - if visited[target_node]: # added 4 - continue - - probability_ = abs(current_probability) * probability - - if probability_ > max_probabilities[target_node]: - max_probabilities[target_node] = probability_ - # It may cause the same `target_node` added into `priority_queue` more than once, but it doesn't matter. Because only the one `heappush`ed first may change the `max_probabilities` data. - heapq.heappush(priority_queue, (-probability_, target_node)) - - return 0 -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1584-min-cost-to-connect-all-points-2.md b/en/1001-2000/1584-min-cost-to-connect-all-points-2.md deleted file mode 100644 index 6bfd92d..0000000 --- a/en/1001-2000/1584-min-cost-to-connect-all-points-2.md +++ /dev/null @@ -1,192 +0,0 @@ -# 1584. Min Cost to Connect All Points - Best Practices of LeetCode Solutions (Kruskal's Algorithm) -LeetCode link: [1584. Min Cost to Connect All Points](https://leetcode.com/problems/min-cost-to-connect-all-points) - -## LeetCode problem description -You are given an array `points` representing integer coordinates of some points on a 2D-plane, where `points[i] = [xi, yi]`. - -The cost of connecting two points `[xi, yi]` and `[xj, yj]` is the manhattan distance between them: `|xi - xj| + |yi - yj|`, where `|val|` denotes the absolute value of `val`. - -Return _the minimum cost to make all points connected_. All points are connected if there is **exactly one** simple path between any two points. - -### Example 1 -![](../../images/examples/1584_1_1.png) -```java -Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]] -Output: 20 -Explanation: -``` -![](../../images/examples/1584_1_2.png) -``` -We can connect the points as shown above to get the minimum cost of 20. -Notice that there is a unique path between every pair of points. -``` - -### Example 2 -```java -Input: points = [[3,12],[-2,5],[-4,1]] -Output: 18 -``` - -### Constraints -- `1 <= points.length <= 1000` -- `-1000000 <= xi, yi <= 1000000` -- All pairs `(xi, yi)` are distinct. - -
- Hint 1 - Connect each pair of points with a weighted edge, the weight being the manhattan distance between those points. -
- -
- Hint 2 - The problem is now the cost of minimum spanning tree in graph with above edges. -
- -## Intuition -* Connect each pair of points with a **weighted** edge, the weight being the manhattan distance between those points. -* Cycles will increase the `cost`, so there is no cycle. -* A connected graph without cycles is called a tree. -* The problem is now the cost of **minimum spanning tree** in graph with above edges. -* A minimum spanning tree (MST) or minimum weight spanning tree is a subset of the edges of a connected, edge-weighted undirected graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight. - -### Another solution: Prim's Algorithm -Please see [1584. Min Cost to Connect All Points (Prim's Algorithm)](1584-min-cost-to-connect-all-points.md). - -This page, I will only talk about the solution of **Kruskal's Algorithm**. - -### Approach: Kruskal's Algorithm -- _Prim's Algorithm_ adds the closest point to the tree each time, while _Kruskal's Algorithm_ adds the shortest edge to the tree each time. -- If both vertices of an edge are already in the tree, this edge can be skipped. Because once this edge is added, a cycle will be formed, which will increase the cost and destroy the structure of the tree. -- To determine whether a cycle will be formed, the **Union-Find** algorithm can be used. -- Traverse all edges once, add up the lengths of the edges and return the sum as the result. -- If you are familiar with the **Union-Find** algorithm, it is easy to solve the problem with _Kruskal's algorithm_. However, this problem does not directly give the `edges` information, and we need to calculate it through the vertex information, which is not difficult, but this causes the algorithm to run slower than _Prim's Algorithm_ because there are too many edges. The more edges, the slower _Kruskal's Algorithm_. - -#### Compare to Prim's Algorithm -For this problem, `points` are given, so using `Prim's Algorithm` would be faster and easier to understand. - -Because if we use `Kruskal's Algorithm`, we have to convert `points` into `edges`, and we will get a fully dense graph. - -The more edges there are, the worse the performance of `Kruskal's Algorithm` will be. - -For sparse graphs, `Kruskal's Algorithm` is much more efficient than `Prim's Algorithm`. - -For problems of `Minimum Spanning Tree` which `edges` are given, we can give priority to using _Kruskal's Algorithm_. - -## Complexity -> `V` is the `points.length`. -> `E` is the `edges.length`. In this problem, the `E` is `V * V`. - -* Time: `O(E * log(E))`. -* Space: `O(V * V)`. - -## Python -The following code can also be implemented by using `heap sort`, but it would be slower. -```python -from collections import deque - -class Solution: - def __init__(self): - self.parents = [] - - def minCostConnectPoints(self, points: List[List[int]]) -> int: - self.parents = list(range(len(points))) - result = 0 - edges = [] - - for i, point in enumerate(points): - for j in range(i + 1, len(points)): - distance = abs(point[0] - points[j][0]) + \ - abs(point[1] - points[j][1]) - edges.append((distance, i, j)) - - edges.sort() - edges = deque(edges) - - while edges: - distance, i, j = edges.popleft() - - if self.is_same_root(i, j): - continue - - self.unite(i, j) - - result += distance - - return result - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) - - self.parents[x] = root - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Python -```python -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1584-min-cost-to-connect-all-points.md b/en/1001-2000/1584-min-cost-to-connect-all-points.md deleted file mode 100644 index b210651..0000000 --- a/en/1001-2000/1584-min-cost-to-connect-all-points.md +++ /dev/null @@ -1,660 +0,0 @@ -# 1584. Min Cost to Connect All Points - Best Practices of LeetCode Solutions (Prim's Algorithm) -LeetCode link: [1584. Min Cost to Connect All Points](https://leetcode.com/problems/min-cost-to-connect-all-points) - -## LeetCode problem description -You are given an array `points` representing integer coordinates of some points on a 2D-plane, where `points[i] = [xi, yi]`. - -The cost of connecting two points `[xi, yi]` and `[xj, yj]` is the manhattan distance between them: `|xi - xj| + |yi - yj|`, where `|val|` denotes the absolute value of `val`. - -Return _the minimum cost to make all points connected_. All points are connected if there is **exactly one** simple path between any two points. - -### Example 1 -![](../../images/examples/1584_1_1.png) -```java -Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]] -Output: 20 -Explanation: -``` -![](../../images/examples/1584_1_2.png) -``` -We can connect the points as shown above to get the minimum cost of 20. -Notice that there is a unique path between every pair of points. -``` - -### Example 2 -```java -Input: points = [[3,12],[-2,5],[-4,1]] -Output: 18 -``` - -### Constraints -- `1 <= points.length <= 1000` -- `-1000000 <= xi, yi <= 1000000` -- All pairs `(xi, yi)` are distinct. - -
- Hint 1 - Connect each pair of points with a weighted edge, the weight being the manhattan distance between those points. -
- -
- Hint 2 - The problem is now the cost of minimum spanning tree in graph with above edges. -
- -## Intuition -* Connect each pair of points with a **weighted** edge, the weight being the manhattan distance between those points. -* Cycles will increase the `cost`, so there is no cycle. -* A connected graph without cycles is called a tree. -* The problem is now the cost of **minimum spanning tree** in graph with above edges. -* A minimum spanning tree (MST) or minimum weight spanning tree is a subset of the edges of a connected, edge-weighted undirected graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight. -* One of the solutions for `MST` is the **Prim algorithm**, which is a _greedy algorithm_ and also a _dynamic programming algorithm_. - -### Another solution: Kruskal's Algorithm -Please see [1584. Min Cost to Connect All Points (Kruskal's Algorithm)](1584-min-cost-to-connect-all-points-2.md). - -This page, I will only talk about the solution of **Prim's Algorithm**. - -### Prim's Algorithm -- Initially, add any point to an empty graph, for example, the point with index 0. -- Next, add the second point. This second point is the **closest** point to the first point. -- An `min_distances` (or call it `dp`) array is needed to store the distances of other points to the first point. -- After the second point is added, add the third point in the same way. The third point is the **closest** point to the first two points. This time, only the distances of other points to the second point need to be calculated, because their distances to the first point have already been calculated and stored in the `min_distances` array. -- Update the `min_distances` array, and the array is a rolling array. -- Finally, all points are added to the graph. - -## Approach -Let us use the _common 5 steps_ to solve a _dynamic programming problem_. - -### Common five steps in dynamic programming -1. Determine the **meaning** of the `min_distances[i]` - * `min_distances[i]` represents the **minimum** `cost` (or call it `weight`, `distance`) of adding `points[i]` into current tree. - * `min_distances[i]` is an integer. -2. Determine the `min_distances` array's initial value - * Use the example 1 `points = [[0,0],[2,2],[3,10],[5,2],[7,0]]`: - ```python - After initialization, the 'min_distances' array would be: - # 0 1 2 3 4 # index - # 0 i i i i # `i` repreents a very large number - ``` -3. Determine the `min_distances` array's recurrence formula - * Try to complete the grid. In the process, you will get inspiration to derive the formula. - ```python - points = [[0,0],[2,2],[3,10],[5,2],[7,0]] - # 0 1 2 3 4 # index - # v 4 13 7 7 # min_distances. current_index will become 1 later becaue 4 is the closet. `v` reprents this point is 'visited', and its value is fixed. - # v v 9 3 7 # min_distances. current_index will become 3 later becaue 3 is the closet - # v v 9 v 4 # min_distances. current_index will become 4 later becaue 4 is the closet - # v v 9 v v # min_distances. current_index will become 2 later becaue it is the last one - # 0 4 9 3 4 # min_distances: 0 + 4 + 9 + 3 + 4 = 20 - ``` - * We can derive the `Recurrence Formula`: - ```python - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + - abs(points[i][1] - points[current_index][1]) - ) - ``` -4. Determine the `min_distances` array's traversal order - * The traversal order doesn't matter. -5. Check the `min_distances` array's value - * Print the `min_distances` to see if it is as expected. - -### Solution 1: Not use 'heap sort' -#### The process of coding -* Initialize `min_distances` and do the first iteration. -```python -min_distances = [float('inf')] * len(points) # This is just the `dp` array -min_distances[0] = 0 - -for i, _ in enumerate(points): - if i == 0: - continue - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[0][0]) + \ - abs(points[i][1] - points[0][1]) - ) -``` - -* Use `current_index` to replace the fixed index `0`: -```python -min_distances = [float('inf')] * len(points) # This is just the `dp` array -min_distances[0] = 0 -current_index = 0 - -for i, _ in enumerate(points): - if i == current_index: - continue - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + \ - abs(points[i][1] - points[current_index][1]) - ) -``` - -* Find the `next_index` of the point which is the **closest** to the existing tree. -```python - class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - min_distances = [float('inf')] * len(points) # This is just the `dp` array - min_distances[0] = 0 - current_index = 0 - next_index = None - min_distance = float('inf') - - for i, _ in enumerate(points): - if i == current_index: - continue - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + \ - abs(points[i][1] - points[current_index][1]) - ) - - if min_distances[i] < min_distance: - min_distance = min_distances[i] - next_index = i - - current_index = next_index -``` - -* Use a loop to add each point. To do so, there are two ways. - -Way 1: Use `pending_indexes` set and only process the indexes in it. -```python -current_index = 0 -pending_indexes = set(range(len(points))) - -while pending_indexes: - pending_indexes.remove(current_index) - - # ... -``` - -Way 2: We need an array named `visited` to record the indexes of the points already added. In the iteration, if a point has been added, just skip it. -```python -current_index = 0 -visited = [False] * len(points) -visited[current_index] = True - -for i, point in enumerate(points): - if visited[i]: - continue - - # ... -``` - -Which way do you prefer? I prefer `way 1` because it's easier to understand. - -* Return `sum(min_distances)`. - -### Solution 2: Use 'heap sort' -* If you use **heap sort**, `current_index`, `next_index`, `minimum_distance` is not needed, because _heap sort_ knows which is the minimum value. -* `visited` is also not needed, because each `heappop()` means that a point has been `visited`. - -## Complexity -`V` is the `points.length`. - -* Time: `O(V * V)`. All those solutions' time complexity are `O(n * n)`, because `heapq.heapify()` is `O(n)`. -* Space: `O(V)`. - -## Python -### Solution 1: Not use 'heap sort' -#### Way 1: Use `pending_indexes` set -```python -class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - min_distances = [float('inf') for _ in points] - min_distances[0] = 0 - current_index = 0 - pending_indexes = set(range(len(points))) - - while pending_indexes: - pending_indexes.remove(current_index) - next_index = None - minimum_distance = float('inf') - - for i in pending_indexes: - distance = get_distance(points[i], points[current_index]) - - if distance < min_distances[i]: - min_distances[i] = distance - - if min_distances[i] < minimum_distance: - minimum_distance = min_distances[i] - next_index = i - - current_index = next_index - - return sum(min_distances) - - -def get_distance(point1, point2): - return abs(point2[0] - point1[0]) + abs(point2[1] - point1[1]) -``` - -#### Way 2: Use `visited` array -```python -class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - min_distances = [float('inf')] * len(points) # This is just the `dp` array - min_distances[0] = 0 - - current_index = 0 - visited = [False] * len(points) - - while current_index is not None: - visited[current_index] = True - next_index = None - minimum_distance = float('inf') - - for i, point in enumerate(points): - if visited[i]: - continue - - distance = \ - abs(point[0] - points[current_index][0]) + \ - abs(point[1] - points[current_index][1]) - - if distance < min_distances[i]: - min_distances[i] = distance - - if min_distances[i] < minimum_distance: - minimum_distance = min_distances[i] - next_index = i - - current_index = next_index - - return sum(min_distances) -``` - -### Solution 2: Use 'heap sort' -```python -class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - result = 0 - min_distances = [[float('inf'), i] for i in range(len(points))] - min_distances[0][0] = 0 - - while min_distances: - distance_, current_index = heapq.heappop(min_distances) - result += distance_ - - for min_distance in min_distances: - point = points[min_distance[1]] - distance = get_distance(point, points[current_index]) - - if distance < min_distance[0]: - min_distance[0] = distance - - heapq.heapify(min_distances) - - return result - - -def get_distance(point1, point2): - return abs(point2[0] - point1[0]) + abs(point2[1] - point1[1]) -``` - -## Java -### Solution 1: Not use 'heap sort' -#### Way 1: Use `pending_indexes` set -```java -class Solution { - public int minCostConnectPoints(int[][] points) { - var minDistances = new int[points.length]; // This is just the `dp` array - Arrays.fill(minDistances, Integer.MAX_VALUE); - minDistances[0] = 0; - - var currentIndex = 0; - var pendingIndexes = new HashSet(); - for (var i = 0; i < points.length; i++) { - pendingIndexes.add(i); - } - - while (!pendingIndexes.isEmpty()) { - pendingIndexes.remove(currentIndex); - - var nextIndex = -1; - var minimumDistance = Integer.MAX_VALUE; - - for (var i : pendingIndexes) { - var distance = - Math.abs(points[i][0] - points[currentIndex][0]) + - Math.abs(points[i][1] - points[currentIndex][1]); - - if (distance < minDistances[i]) { - minDistances[i] = distance; - } - - if (minDistances[i] < minimumDistance) { - minimumDistance = minDistances[i]; - nextIndex = i; - } - } - - currentIndex = nextIndex; - } - - return IntStream.of(minDistances).sum(); - } -} -``` - -#### Way 2: Use `visited` array -```java -class Solution { - public int minCostConnectPoints(int[][] points) { - var minDistances = new int[points.length]; // This is just the `dp` array - Arrays.fill(minDistances, Integer.MAX_VALUE); - minDistances[0] = 0; - - var currentIndex = 0; - var visited = new boolean[points.length]; - - while (currentIndex != -1) { - visited[currentIndex] = true; - var nextIndex = -1; - var minDistance = Integer.MAX_VALUE; - - for (var i = 0; i < points.length; i++) { - if (visited[i]) { - continue; - } - - minDistances[i] = Math.min( - minDistances[i], - Math.abs(points[i][0] - points[currentIndex][0]) + - Math.abs(points[i][1] - points[currentIndex][1]) - ); - - if (minDistances[i] < minDistance) { - minDistance = minDistances[i]; - nextIndex = i; - } - } - - currentIndex = nextIndex; - } - - return IntStream.of(minDistances).sum(); - } -} -``` - -### Solution 2: Use 'heap sort' -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```cpp -class Solution { -public: - int minCostConnectPoints(vector>& points) { - auto min_distances = vector(points.size(), INT_MAX); // This is just the `dp` array - min_distances[0] = 0; - - auto current_index = 0; - auto visited = vector(points.size()); - - while (current_index != -1) { - visited[current_index] = true; - auto next_index = -1; - auto min_distance = INT_MAX; - - for (auto i = 0; i < points.size(); i++) { - if (visited[i]) { - continue; - } - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + - abs(points[i][1] - points[current_index][1]) - ); - - if (min_distances[i] < min_distance) { - min_distance = min_distances[i]; - next_index = i; - } - } - - current_index = next_index; - } - - return reduce(min_distances.begin(), min_distances.end()); - } -}; -``` - -### Solution 2: Use 'heap sort' -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```javascript -var minCostConnectPoints = function (points) { - const minDistances = Array(points.length).fill(Number.MAX_SAFE_INTEGER) // This is just the `dp` array - minDistances[0] = 0 - - let currentIndex = 0 - const visited = Array(points.length).fill(false) - - while (currentIndex != -1) { - visited[currentIndex] = true - let nextIndex = -1 - let minDistance = Number.MAX_SAFE_INTEGER - - for (let i = 0; i < points.length; i++) { - if (visited[i]) { - continue - } - - minDistances[i] = Math.min( - minDistances[i], - Math.abs(points[i][0] - points[currentIndex][0]) + - Math.abs(points[i][1] - points[currentIndex][1]) - ) - - if (minDistances[i] < minDistance) { - minDistance = minDistances[i] - nextIndex = i - } - } - - currentIndex = nextIndex - } - - return _.sum(minDistances) -}; -``` - -### Solution 2: Use 'heap sort' -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```c# -public class Solution -{ - public int MinCostConnectPoints(int[][] points) - { - var minDistances = new int[points.Length]; // This is just the `dp` array - Array.Fill(minDistances, Int32.MaxValue); - minDistances[0] = 0; - - int currentIndex = 0; - var visited = new bool[points.Length]; - - while (currentIndex != -1) - { - visited[currentIndex] = true; - int nextIndex = -1; - int minDistance = Int32.MaxValue; - - for (int i = 0; i < points.Length; i++) - { - if (visited[i]) - { - continue; - } - - minDistances[i] = Math.Min( - minDistances[i], - Math.Abs(points[i][0] - points[currentIndex][0]) + - Math.Abs(points[i][1] - points[currentIndex][1]) - ); - - if (minDistances[i] < minDistance) - { - minDistance = minDistances[i]; - nextIndex = i; - } - } - - currentIndex = nextIndex; - } - - return minDistances.Sum(); - } -} -``` - -### Solution 2: Use 'heap sort' -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```go -func minCostConnectPoints(points [][]int) int { - minDistances := slices.Repeat([]int{math.MaxInt32}, len(points)) // This is just the `dp` array - minDistances[0] = 0 - - currentIndex := 0 - visited := make([]bool, len(points)) - - for currentIndex != -1 { - visited[currentIndex] = true - nextIndex := -1 - minDistance := math.MaxInt32 - - for i, point := range points { - if visited[i] { - continue - } - - minDistances[i] = min( - minDistances[i], - int( - math.Abs(float64(point[0] - points[currentIndex][0])) + - math.Abs(float64(point[1] - points[currentIndex][1])), - ), - ) - - if minDistances[i] < minDistance { - minDistance = minDistances[i] - nextIndex = i - } - } - - currentIndex = nextIndex - } - - distanceSum := 0 - for _, distance := range minDistances { - distanceSum += distance - } - - return distanceSum -} -``` - -### Solution 2: Use 'heap sort' -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```ruby -def min_cost_connect_points(points) - min_distances = Array.new(points.size, Float::INFINITY) # This is just the `dp` array. - min_distances[0] = 0 - - current_index = 0 - visited = Array.new(points.size, false) - - while !current_index.nil? - visited[current_index] = true - next_index = nil - min_distance = Float::INFINITY - - points.each_with_index do |point, i| - next if visited[i] - - min_distances[i] = [ - min_distances[i], - (point[0] - points[current_index][0]).abs + - (point[1] - points[current_index][1]).abs - ].min - - if min_distances[i] < min_distance - min_distance = min_distances[i] - next_index = i - end - end - - current_index = next_index - end - - min_distances.sum -end -``` - -### Solution 2: Use 'heap sort' -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1768-merge-strings-alternately.md b/en/1001-2000/1768-merge-strings-alternately.md deleted file mode 100644 index a0c5cef..0000000 --- a/en/1001-2000/1768-merge-strings-alternately.md +++ /dev/null @@ -1,243 +0,0 @@ -# 1768. Merge Strings Alternately - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [1768. Merge Strings Alternately - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1768-merge-strings-alternately) for a better experience! - -LeetCode link: [1768. Merge Strings Alternately](https://leetcode.com/problems/merge-strings-alternately), difficulty: **Easy**. - -## LeetCode description of "1768. Merge Strings Alternately" - -You are given two strings `word1` and `word2`. Merge the strings by adding letters in alternating order, starting with `word1`. If a string is longer than the other, append the additional letters onto the end of the merged string. - -Return *the merged string*. - -### [Example 1] - -**Input**: `word1 = "abc", word2 = "pqr"` - -**Output**: `"apbqcr"` - -**Explanation**: - -
The merged string will be merged as so:
-word1:  a   b   c
-word2:    p   q   r
-merged: a p b q c r
-
- -### [Example 2] - -**Input**: `word1 = "ab", word2 = "pqrs"` - -**Output**: `"apbqrs"` - -**Explanation**: - -
Notice that as word2 is longer, "rs" is appended to the end.
-word1:  a   b 
-word2:    p   q   r   s
-merged: a p b q   r   s
-
- -### [Example 3] - -**Input**: `word1 = "abcd", word2 = "pq"` - -**Output**: `"apbqcd"` - -**Explanation**: - -
Notice that as word1 is longer, "cd" is appended to the end.
-word1:  a   b   c   d
-word2:    p   q 
-merged: a p b q c   d
-
- -### [Constraints] - -- `1 <= word1.length, word2.length <= 100` -- `word1` and `word2` consist of lowercase English letters. - -### [Hints] - -
- Hint 1 - Use two pointers, one pointer for each string. Alternately choose the character from each pointer, and move the pointer upwards. - - -
- -## Intuition - -The problem asks us to merge two strings, `word1` and `word2`, by taking characters alternately, starting with `word1`. If one string is longer than the other, the remaining characters of the longer string should be appended to the end of the merged result. - -The core idea is to iterate through both strings simultaneously, picking one character from `word1` and then one from `word2`, and adding them to our result. This process continues as long as we have characters available in *both* strings. - -Once we run out of characters in the shorter string, we simply take all the remaining characters from the longer string and append them to our result. - -## Step by Step Solutions - -1. Initialize an empty string (or a list of characters, or a string builder) to store the merged result. -2. Determine the lengths of `word1` and `word2`. Let these be `n1` and `n2`. -3. Find the minimum of these two lengths, say `min_len = min(n1, n2)`. This `min_len` is the number of characters we can pick alternately from both strings. -4. Iterate from `i = 0` up to `min_len - 1`: - - Append the `i`-th character of `word1` to the result. - - Append the `i`-th character of `word2` to the result. -5. After the loop, we have processed `min_len` characters from both strings. -6. Determine which string potentially has leftover characters. Let this be `longer_word`. - - If the length of `word1` (`n1`) is greater than `min_len`, then `longer_word` is `word1`. - - Otherwise `longer_word` is `word2`. -7. Append the remaining part of `longer_word` (i.e., `longer_word` from index `min_len` onwards) to the `result`. -8. Return the final merged string. - -## Complexity - -- Time complexity: `O(N)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def mergeAlternately(self, word1: str, word2: str) -> str: - min_size = min(len(word1), len(word2)) - result = "" - - for i in range(min_size): - result += f'{word1[i]}{word2[i]}' - - longer_word = word1 if len(word1) > min_size else word2 - - return result + longer_word[min_size:] -``` - -## Java - -```java -class Solution { - public String mergeAlternately(String word1, String word2) { - int minSize = Math.min(word1.length(), word2.length()); - StringBuilder result = new StringBuilder(); - - for (int i = 0; i < minSize; i++) { - result.append(word1.charAt(i)).append(word2.charAt(i)); - } - - String longerWord = (word1.length() > word2.length()) ? word1 : word2; - result.append(longerWord.substring(minSize)); - - return result.toString(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string mergeAlternately(string word1, string word2) { - int min_size = min(word1.length(), word2.length()); - string result; - - for (int i = 0; i < min_size; ++i) { - result += word1[i]; - result += word2[i]; - } - - auto& longer_word = (word1.length() > min_size) ? word1 : word2; - result += longer_word.substr(min_size); - - return result; - } -}; -``` - -## JavaScript - -```javascript -var mergeAlternately = function(word1, word2) { - const minSize = Math.min(word1.length, word2.length); - let result = ""; - - for (let i = 0; i < minSize; i++) { - result += word1[i] + word2[i]; - } - - const longerWord = word1.length > word2.length ? word1 : word2; - result += longerWord.slice(minSize); - - return result; -}; -``` - -## Go - -```go -func mergeAlternately(word1, word2 string) string { - minSize := int(math.Min(float64(len(word1)), float64(len(word2)))) - var result strings.Builder - - for i := 0; i < minSize; i++ { - result.WriteByte(word1[i]) - result.WriteByte(word2[i]) - } - - longerWord := word1 - if len(word2) > len(word1) { - longerWord = word2 - } - result.WriteString(longerWord[minSize:]) - - return result.String() -} -``` - -## C# - -```csharp -public class Solution -{ - public string MergeAlternately(string word1, string word2) - { - int minSize = Math.Min(word1.Length, word2.Length); - var result = new StringBuilder(); - - for (int i = 0; i < minSize; i++) - result.Append(word1[i]).Append(word2[i]); - - string longerWord = word1.Length > word2.Length ? word1 : word2; - result.Append(longerWord.Substring(minSize)); - - return result.ToString(); - } -} -``` - -## Ruby - -```ruby -def merge_alternately(word1, word2) - min_size = [ word1.size, word2.size ].min - result = "" - - min_size.times { |i| result << word1[i] << word2[i] } - - longer_word = word1.size > word2.size ? word1 : word2 - result << longer_word[min_size..] - - result -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [1768. Merge Strings Alternately - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/1768-merge-strings-alternately). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/1001-2000/1971-find-if-path-exists-in-graph-2.md b/en/1001-2000/1971-find-if-path-exists-in-graph-2.md deleted file mode 100644 index cee739d..0000000 --- a/en/1001-2000/1971-find-if-path-exists-in-graph-2.md +++ /dev/null @@ -1,435 +0,0 @@ -# LeetCode 1971. Find if Path Exists in Graph's Solution: UnionFind -LeetCode link: [1971. Find if Path Exists in Graph](https://leetcode.com/problems/find-if-path-exists-in-graph) - -## LeetCode problem description -There is a **bi-directional** graph with `n` vertices, where each vertex is labeled from `0` to `n - 1` (**inclusive**). The edges in the graph are represented as a 2D integer array `edges`, where each `edges[i] = [ui, vi]` denotes a bi-directional edge between vertex `ui` and vertex `vi`. Every vertex pair is connected by **at most one** edge, and no vertex has an edge to itself. - -You want to determine if there is a **valid path** that exists from vertex `source` to vertex `destination`. - -Given `edges` and the integers `n`, `source`, and `destination`, return `true` _if there is a **valid path** from `source` to `destination`, or `false` otherwise_. - -### Example 1 -![](../../images/examples/1971_1.png) -``` -Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2 -Output: true -Explanation: There are two paths from vertex 0 to vertex 2: -- 0 → 1 → 2 -- 0 → 2 -``` - -### Example 2 -![](../../images/examples/1971_2.png) -``` -Input: n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5 -Output: false -Explanation: There is no path from vertex 0 to vertex 5. -``` - -### Constraints -- `1 <= n <= 2 * 10^5` -- `0 <= edges.length <= 2 * 10^5` -- `edges[i].length == 2` -- `0 <= ui, vi <= n - 1` -- `ui != vi` -- `0 <= source, destination <= n - 1` -- There are no duplicate edges. -- There are no self edges. - -## Another solution: Breadth-First Search Algorithm -Please see [1971. Find if Path Exists in Graph ('Breadth-First Search' Solution)](1971-find-if-path-exists-in-graph.md). - -## Intuition -This graph may have multiple **connected components**. - -![](../../images/graph_undirected_2.png) - -- Initially, we start from `source` vertex which belongs to one of the `connected components`. -- We need to find if there is a path from `source` to `destination`. This question is equivalent to determine if `source` and `destination` vertices belong to the same `connected component`. -- A `tree` is a type of `graph`. If two nodes are in the same tree, then return `true`. So we need a method `in_same_tree(node1, node2)` to return a boolean value. -- We are given `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**. -- `UnionFind` algorithm is designed for grouping and searching data. - -### 'UnionFind' algorithm -- `UnionFind` algorithm typically has three methods: - - The `unite(node1, node2)` operation can be used to merge two trees. - - The `find_root(node)` method can be used to return the root of a node. - - The `is_same_root(node1, node2)` method is used to determine whether two nodes are in the same tree. - -## Approach (UnionFind algorithm) -1. Initially, each node is in its own group. -1. Iterate `edges` data and `unite(node1, node2)`. -1. Return `is_same_root(source, destination)`. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Standard UnionFind algorithm (recommended) -```python -class Solution: - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - self.parents = list(range(n)) - - for x, y in edges: - self.unite(x, y) - - return self.is_same_root(source, destination) - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x # Error-prone point 1 - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) # Error-prone point 2 - - self.parents[x] = root # Error-prone point 3 - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -### Another UnionFind algorithm (using a map and an array of set) -* This solution is slower than the `standard UnionFind algorithm`, but it is straightforward. -* The applicability of this solution is not as wide as the `standard UnionFind algorithm` because data in a set don't have association, yet the `standard UnionFind algorithm` has a `parents` array with association of nodes. -* The `standard UnionFind algorithm` should be the first choice instead of this one. - -```python -class Solution: - def __init__(self): - self.disjoint_sets = [] - self.value_to_set_id = {} - - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - for i in range(n): - self.disjoint_sets.append({i}) - self.value_to_set_id[i] = i - - for x, y in edges: - self.unite(x, y) - - return self.in_same_set(source, destination) - - def unite(self, x, y): - if self.in_same_set(x, y): - return - - bigger = x - smaller = y - - if len(self.get_set(x)) < len(self.get_set(y)): - bigger = y - smaller = x - - for value in self.get_set(smaller): - self.get_set(bigger).add(value) - self.value_to_set_id[value] = self.value_to_set_id.get(bigger) - - def get_set(self, value): - set_id = self.value_to_set_id.get(value) - return self.disjoint_sets[set_id] - - def in_same_set(self, x, y): - return self.get_set(x) == self.get_set(y) -``` - -## Java -```java -class Solution { - private int[] parents; - - public boolean validPath(int n, int[][] edges, int source, int destination) { - parents = new int[n]; - - for (var i = 0; i < n; i++) { - parents[i] = i; - } - - for (var edge : edges) { - unite(edge[0], edge[1]); - } - - return isSameRoot(source, destination); - } - - private void unite(int x, int y) { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - private int findRoot(int x) { - var parent = parents[x]; - - if (x == parent) { - return x; - } - - var root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - private boolean isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -} -``` - -## C++ -```cpp -class Solution { -public: - bool validPath(int n, vector>& edges, int source, int destination) { - for (auto i = 0; i < n; i++) { - parents.push_back(i); - } - - for (auto& edge : edges) { - unite(edge[0], edge[1]); - } - - return isSameRoot(source, destination); - } - -private: - vector parents; - - void unite(int x, int y) { - int root_x = findRoot(x); - int root_y = findRoot(y); - - parents[root_y] = root_x; // Error-prone point 1 - } - - int findRoot(int x) { - auto parent = parents[x]; - - if (x == parent) { - return x; - } - - auto root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -}; -``` - -## JavaScript -```javascript -let parents - -var validPath = function (n, edges, source, destination) { - parents = [] - for (let i = 0; i < n; i++) { - parents.push(i) - } - - for (const [a, b] of edges) { - unite(a, b) - } - - return isSameRoot(source, destination) -}; - -function unite(x, y) { - rootX = findRoot(x) - rootY = findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -function findRoot(x) { - const parent = parents[x] - - if (x == parent) { - return x - } - - const root = findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -function isSameRoot(x, y) { - return findRoot(x) == findRoot(y) -} -``` - -## C# -```c# -public class Solution -{ - int[] parents; - - public bool ValidPath(int n, int[][] edges, int source, int destination) - { - parents = new int[n]; - - for (int i = 0; i < n; i++) - parents[i] = i; - - foreach (int[] edge in edges) - { - unite(edge[0], edge[1]); - } - - return isSameRoot(source, destination); - } - - void unite(int x, int y) - { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - int findRoot(int x) - { - int parent = parents[x]; - - if (x == parent) - return x; - - int root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) - { - return findRoot(x) == findRoot(y); - } -} -``` - -## Go -```go -var parents []int - -func validPath(n int, edges [][]int, source int, destination int) bool { - parents = make([]int, n) - for i := 0; i < n; i++ { - parents[i] = i - } - - for _, edge := range edges { - unite(edge[0], edge[1]) - } - - return isSameRoot(source, destination) -} - -func unite(x, y int) { - rootX := findRoot(x) - rootY := findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -func findRoot(x int) int { - parent := parents[x]; - - if x == parent { - return x - } - - root := findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -func isSameRoot(x, y int) bool { - return findRoot(x) == findRoot(y) -} -``` - -## Ruby -```ruby -def valid_path(n, edges, source, destination) - @parents = (0...n).to_a - - edges.each do |edge| - unite(edge[0], edge[1]) - end - - is_same_root(source, destination) -end - -def unite(x, y) - root_x = find_root(x) - root_y = find_root(y) - - @parents[root_y] = root_x # Error-prone point 1 -end - -def find_root(x) - parent = @parents[x] - - if x == parent - return x - end - - root = find_root(parent) # Error-prone point 2 - - @parents[x] = root # Error-prone point 3 - - root -end - -def is_same_root(x, y) - find_root(x) == find_root(y) -end -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/1001-2000/1971-find-if-path-exists-in-graph.md b/en/1001-2000/1971-find-if-path-exists-in-graph.md deleted file mode 100644 index 4e62c0d..0000000 --- a/en/1001-2000/1971-find-if-path-exists-in-graph.md +++ /dev/null @@ -1,188 +0,0 @@ -# LeetCode 1971. Find if Path Exists in Graph's Solution (Breadth-First Search) -LeetCode link: [1971. Find if Path Exists in Graph](https://leetcode.com/problems/find-if-path-exists-in-graph) - -## LeetCode problem description -There is a **bi-directional** graph with `n` vertices, where each vertex is labeled from `0` to `n - 1` (**inclusive**). The edges in the graph are represented as a 2D integer array `edges`, where each `edges[i] = [ui, vi]` denotes a bi-directional edge between vertex `ui` and vertex `vi`. Every vertex pair is connected by **at most one** edge, and no vertex has an edge to itself. - -You want to determine if there is a **valid path** that exists from vertex `source` to vertex `destination`. - -Given `edges` and the integers `n`, `source`, and `destination`, return `true` _if there is a **valid path** from `source` to `destination`, or `false` otherwise_. - -### Example 1 -![](../../images/examples/1971_1.png) -``` -Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2 -Output: true -Explanation: There are two paths from vertex 0 to vertex 2: -- 0 → 1 → 2 -- 0 → 2 -``` - -### Example 2 -![](../../images/examples/1971_2.png) -``` -Input: n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5 -Output: false -Explanation: There is no path from vertex 0 to vertex 5. -``` - -### Constraints -- `1 <= n <= 2 * 10^5` -- `0 <= edges.length <= 2 * 10^5` -- `edges[i].length == 2` -- `0 <= ui, vi <= n - 1` -- `ui != vi` -- `0 <= source, destination <= n - 1` -- There are no duplicate edges. -- There are no self edges. - -## Another solution: UnionFind Algorithm -Please see [1971. Find if Path Exists in Graph (UnionFind Solution)](1971-find-if-path-exists-in-graph-2.md). - -## Intuition -This graph may have multiple **connected components**. - -![](../../images/graph_undirected_2.png) - -Initially, we start from `source` vertex which belongs to one of the `connected components`. -We need to find if there is a path from `source` to `destination`. This question is equivalent to determine if `source` and `destination` vertices belong to the same `connected component`. - -### Breadth-First Search -* There are two major ways to explore a `connected component`: **Breadth-First Search** and **Depth-First Search**. -* For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. Please see [200. Number of Islands (Depth-First Search)](../1-1000/200-number-of-islands.md). - -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **breadth-first search** can be thought of as visiting vertices in rounds and rounds. - -* `breadth-first search` emphasizes first-in-first-out, so a **queue** is needed. - -## Approach (Breadth-First Search) -1. Starting at the `source` vertex, find all the vertices of the `connected component` by `breadth-first search`. -1. In order to conduct `breadth-first search`, we need to know the adjacent vertices of a vertex. So we need a `map` `vertex_to_adjacent_vertices`. We can initialize the `map` by transforming `edges`. -1. We need to mark all vertices on the same connected component as vertex `source` as `visited` because visited vertices don't need to be visited again. -1. Once vertex `destination` is encountered, return `true`. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Breadth-first search -```python -class Solution: - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - vertex_queue = deque([source]) - visited_vertices = set([source]) - - vertex_to_adjacent_vertices = defaultdict(list) - for vertex0, vertex1 in edges: - vertex_to_adjacent_vertices[vertex0].append(vertex1) - vertex_to_adjacent_vertices[vertex1].append(vertex0) - - while vertex_queue: - vertex = vertex_queue.popleft() - - if vertex == destination: - return True - - for adjacent_vertex in vertex_to_adjacent_vertices[vertex]: - if adjacent_vertex not in visited_vertices: - vertex_queue.append(adjacent_vertex) - visited_vertices.add(adjacent_vertex) # Mark visited as soon as `vertex_queue.append(adjacent_vertex)`. Otherwise it may have performance issue! - - return False -``` - -### Depth-first search (more complex) -```python -class Solution: - def __init__(self): - self.visited = set() - self.found = False - - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - if source == destination: - return True - - self.destination = destination - self.vertex_to_vertices = defaultdict(list) - - for vertex1, vertex2 in edges: - self.vertex_to_vertices[vertex1].append(vertex2) - self.vertex_to_vertices[vertex2].append(vertex1) - - self.depth_first_search(source) - - return self.found - - def depth_first_search(self, vertex_): - if self.found: - return - - for vertex in self.vertex_to_vertices[vertex_]: - if vertex == self.destination: - self.found = True - return - - if vertex in self.visited: - continue - - self.visited.add(vertex) - self.depth_first_search(vertex) -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/en/2001-3000/.keep b/en/2001-3000/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/en/3001-4000/.keep b/en/3001-4000/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/en/3001-4000/3478-choose-k-elements-with-maximum-sum.md b/en/3001-4000/3478-choose-k-elements-with-maximum-sum.md deleted file mode 100644 index 8a7293f..0000000 --- a/en/3001-4000/3478-choose-k-elements-with-maximum-sum.md +++ /dev/null @@ -1,137 +0,0 @@ -# 3478. Choose K Elements With Maximum Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [3478. Choose K Elements With Maximum Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/3478-choose-k-elements-with-maximum-sum) for a better experience! - -LeetCode link: [3478. Choose K Elements With Maximum Sum](https://leetcode.com/problems/choose-k-elements-with-maximum-sum), difficulty: **Medium**. - -## LeetCode description of "3478. Choose K Elements With Maximum Sum" - -You are given two integer arrays, `nums1` and `nums2`, both of length `n`, along with a positive integer `k`. - -For each index `i` from `0` to `n - 1`, perform the following: - -- Find all indices `j` where `nums1[j]` is less than `nums1[i]`. -- Choose at most `k` values of `nums2[j]` at these indices to maximize the total sum. - -Return an array `answer` of size `n`, where `answer[i]` represents the result for the corresponding index `i`. - -### [Example 1] - -**Input**: `nums1 = [4,2,1,5,3], nums2 = [10,20,30,40,50], k = 2` - -**Output**: `[80,30,0,80,50]` - -**Explanation**: - -
    -
  • For i = 0: Select the 2 largest values from nums2 at indices [1, 2, 4] where nums1[j] < nums1[0], resulting in 50 + 30 = 80.
  • -
  • For i = 1: Select the 2 largest values from nums2 at index [2] where nums1[j] < nums1[1], resulting in 30.
  • -
  • For i = 2: No indices satisfy nums1[j] < nums1[2], resulting in 0.
  • -
  • For i = 3: Select the 2 largest values from nums2 at indices [0, 1, 2, 4] where nums1[j] < nums1[3], resulting in 50 + 30 = 80.
  • -
  • For i = 4: Select the 2 largest values from nums2 at indices [1, 2] where nums1[j] < nums1[4], resulting in 30 + 20 = 50.
  • -
- - -### [Example 2] - -**Input**: `nums1 = [2,2,2,2], nums2 = [3,1,2,3], k = 1` - -**Output**: `[0,0,0,0]` - -**Explanation**: - -

Since all elements in nums1 are equal, no indices satisfy the condition nums1[j] < nums1[i] for any i, resulting in 0 for all positions.

- - -### [Constraints] - -- `n == nums1.length == nums2.length` -- `1 <= n <= 10^5` -- `1 <= nums1[i], nums2[i] <= 10^6` -- `1 <= k <= n` - -### [Hints] - -
- Hint 1 - Sort `nums1` and its corresponding `nums2` values together based on `nums1`. - - -
- -
- Hint 2 - Use a max heap to track the top `k` values of `nums2` as you process each element in the sorted order. - - -
- -## Intuition - -* Seeing this, everyone will definitely think of sorting `nums1` from small to large, so that the front is less than or equal to the back, but the indexes will be **messy** when sorting. If there is no good way to solve this problem, the whole question cannot be solved. Please think about it first. - -
Click to view the answer

Bring the `index` when sorting, that is, the object to be sorted is an array of tuples of `(num, index)`. This technique **must be mastered**, as it will be used in many questions.

- - After solving the above problems, the indexes are all there, let's continue reading: - -* Requirement 2: Choose at most `k` values of `nums2[j]` at these indices to **maximize** the total sum. - - After seeing this, have you thought of any good method? - -
Click to view the answer

Heap sort, maintain a large root heap of size `k`. This is also a knowledge point that is often tested, **must be mastered**.

- - Seeing this, please implement the code according to the above prompts. - -* Finally, it is found that the repeated `num` that appear continuously should be specially processed, that is, the values ​​in `answer` corresponding to the same `num` should be the same. There are many ways to deal with it. What is the simplest way to deal with it? - -
Click to view the answer

Use a `Map`, `key` is `num`, and the same `key` directly uses the `value` corresponding to `key`.

- -## Complexity - -- Time complexity: `O(N * logN)`. -- Space complexity: `O(N)`. - -## Python - -```python -class Solution: - def findMaxSum(self, nums1: List[int], nums2: List[int], k: int) -> List[int]: - num_index_list = [(num, index) for index, num in enumerate(nums1)] # key 1 - num_index_list.sort() - - answer = [None] * len(nums1) - k_max_nums = [] - sum_ = 0 - num_to_sum = defaultdict(int) # key 2 - - for i, num_index in enumerate(num_index_list): - num, index = num_index - - if num in num_to_sum: - answer[index] = num_to_sum[num] - else: - answer[index] = sum_ - num_to_sum[num] = sum_ - - heapq.heappush(k_max_nums, nums2[index]) - sum_ += nums2[index] - - if len(k_max_nums) > k: - num = heapq.heappop(k_max_nums) # key 3 - sum_ -= num - - return answer -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [3478. Choose K Elements With Maximum Sum - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/3478-choose-k-elements-with-maximum-sum). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/3001-4000/3494-find-the-minimum-amount-of-time-to-brew-potions.md b/en/3001-4000/3494-find-the-minimum-amount-of-time-to-brew-potions.md deleted file mode 100644 index 52cbccd..0000000 --- a/en/3001-4000/3494-find-the-minimum-amount-of-time-to-brew-potions.md +++ /dev/null @@ -1,440 +0,0 @@ -# 3494. Find the Minimum Amount of Time to Brew Potions - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions - -Visit original link: [3494. Find the Minimum Amount of Time to Brew Potions - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/3494-find-the-minimum-amount-of-time-to-brew-potions) for a better experience! - -LeetCode link: [3494. Find the Minimum Amount of Time to Brew Potions](https://leetcode.com/problems/find-the-minimum-amount-of-time-to-brew-potions), difficulty: **Medium**. - -## LeetCode description of "3494. Find the Minimum Amount of Time to Brew Potions" - -You are given two integer arrays, `skill` and `mana`, of length `n` and `m`, respectively. - -In a laboratory, `n` wizards must brew `m` potions in order. Each potion has a mana capacity `mana[j]` and **must** pass through **all** the wizards sequentially to be brewed properly. The time taken by the ith wizard on the *jth* potion is *timeij* = `skill[i] * mana[j]`. - -Since the brewing process is delicate, a potion **must** be passed to the next wizard immediately after the current wizard completes their work. This means the timing must be synchronized so that each wizard begins working on a potion **exactly** when it arrives. - -Return the **minimum** amount of time required for the potions to be brewed properly. - -### [Example 1] - -**Input**: `skill = [1,5,2,4], mana = [5,1,4,2]` - -**Output**: `110` - -**Explanation**: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Potion IDStart TimeWizard 0 Done TimeWizard 1 Done TimeWizard 2 Done TimeWizard 3 Done Time
005304060
15253586064
254587886102
3868898102110
- -

As an example for why wizard 0 cannot start working on the 1st potion before time t = 52, consider the case where the wizards started preparing the 1st potion at time t = 50. At time t = 58, wizard 2 is done with the 1st potion, but wizard 3 will still be working on the 0th potion till time t = 60.

- - -### [Example 2] - -**Input**: `skill = [1,1,1], mana = [1,1,1]` - -**Output**: `5` - -**Explanation**: - -
    -
  1. Preparation of the 0th potion begins at time t = 0, and is completed by time t = 3.
  2. -
  3. Preparation of the 1st potion begins at time t = 1, and is completed by time t = 4.
  4. -
  5. Preparation of the 2nd potion begins at time t = 2, and is completed by time t = 5.
  6. -
- - -### [Example 3] - -**Input**: `skill = [1,2,3,4], mana = [1,2]` - -**Output**: `21` - -### [Constraints] - -- `n == skill.length` -- `m == mana.length` -- `1 <= n, m <= 5000` -- `1 <= mana[i], skill[i] <= 5000` - -### [Hints] - -
- Hint 1 - Maintain each wizard's earliest free time (for the last potion) as `f[i]`. - - -
- -
- Hint 2 - Let `x` be the current mana value. Starting from `now = f[0]`, update `now = max(now + skill[i - 1] * x, f[i])` for `i in [1..n]`. Then, the final `f[n - 1] = now + skill[n - 1] * x` for this potion. - - -
- -
- Hint 3 - Update all other `f` values by `f[i] = f[i + 1] - skill[i + 1] * x` for `i in [0..n - 2]` (in reverse order). - - -
- -## Intuition - -- The first step to solve this problem is to determine what algorithm to use. Because the production of each bottle of potion depends on the completion of the previous bottle of potion in the hands of some wizards, and the potion itself needs to be produced bottle by bottle, so what algorithm should be used? -
Click to view the answer

Dynamic Programming.

- -## Pattern of "Dynamic Programming" - -"Dynamic Programming" requires the use of the `dp` array to store the results. The value of `dp[i][j]` can be converted from its previous (or multiple) values ​​through a formula. Therefore, the value of `dp[i][j]` is derived step by step, and it is related to the previous `dp` record value. - -#### "Dynamic programming" is divided into five steps - -1. Determine the **meaning** of each value of the array `dp`. -2. Initialize the value of the array `dp`. -3. Fill in the `dp` grid data **in order** according to an example. -4. Based on the `dp` grid data, derive the **recursive formula**. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - -#### Detailed description of these five steps - -1. Determine the **meaning** of each value of the array `dp`. - - First determine whether `dp` is a one-dimensional array or a two-dimensional array. A `one-dimensional rolling array` means that the values ​​of the array are overwritten at each iteration. Most of the time, using `one-dimensional rolling array` instead of `two-dimensional array` can simplify the code; but for some problems, such as operating "two swappable arrays", for the sake of ease of understanding, it is better to use `two-dimensional array`. - - Try to use the meaning of the `return value` required by the problem as the meaning of `dp[i]` (one-dimensional) or `dp[i][j]` (two-dimensional). It works about 60% of the time. If it doesn't work, try other meanings. - - Try to save more information in the design. Repeated information only needs to be saved once in a `dp[i]`. - - Use simplified meanings. If the problem can be solved with `boolean value`, don't use `numeric value`. -2. Initialize the value of the array `dp`. The value of `dp` involves two levels: - 1. The length of `dp`. Usually: `condition array length plus 1` or `condition array length`. - 2. The value of `dp[i]` or `dp[i][j]`. `dp[0]` or `dp[0][0]` sometimes requires special treatment. -3. Fill in the `dp` grid data **in order** according to an example. - - The "recursive formula" is the core of the "dynamic programming" algorithm. But the "recursive formula" is obscure. If you want to get it, you need to make a table and use data to inspire yourself. - - If the original example is not good enough, you need to redesign one yourself. - - According to the example, fill in the `dp` grid data "in order", which is very important because it determines the traversal order of the code. - - Most of the time, from left to right, from top to bottom. But sometimes it is necessary to traverse from right to left, from bottom to top, from the middle to the right (or left), such as the "palindrome" problems. Sometimes, it is necessary to traverse a line twice, first forward and then backward. - - When the order is determined correctly, the starting point is determined. Starting from the starting point, fill in the `dp` grid data "in order". This order is also the order in which the program processes. - - In this process, you will get inspiration to write a "recursive formula". If you can already derive the formula, you do not need to complete the grid. -4. Based on the `dp` grid data, derive the **recursive formula**. - - There are three special positions to pay attention to: `dp[i - 1][j - 1]`, `dp[i - 1][j]` and `dp[i][j - 1]`, the current `dp[i][j]` often depends on them. - - When operating "two swappable arrays", due to symmetry, we may need to use `dp[i - 1][j]` and `dp[i][j - 1]` at the same time. -5. Write a program and print the `dp` array. If it is not as expected, adjust it. - - Focus on analyzing those values that are not as expected. - -After reading the above, do you feel that "dynamic programming" is not that difficult? Try to solve this problem. 🤗 - -## Step by Step Solutions - -1. Determine the meaning of each value of the array `dp`. So what does each `dp[i][j]` represent? - mark-detail The row represents the potion, and the column represents the wizard, which has been hinted in the question.
The meaning is: the time it takes for the `j`th wizard to complete the `i`th bottle of potion. I deliberately did not add the word "shortest" because the potion cannot be separated from the hands of the wizard during the manufacturing process! mark-detail -2. How to initialize the group value? - mark-detail Just set all the values to `0`. mark-detail -3. Fill in the `dp` grid data "in order" according to an example. How to do it? - mark-detail The data in the table given in "Example 1" fully meets our needs, so just use it directly. mark-detail -4. Based on the `dp` grid data, derive the "recursive formula". What it the "recursive formula"? - mark-detail Condition 1: After the `j-1`th wizard has finished his work on the `i`th bottle of potion, the `j`th wizard can start his work on the `i`th bottle of potion.
Condition 2: After the `j`th wizard has finished his work on the `i-1`th bottle of potion, he can start his work on the `i`th bottle of potion.
Condition 3: After the `j`th wizard finishes his work on the `i`th potion, the `j+1`th wizard must immediately start his work on the `i`th potion. That is, the potion cannot wait for anyone, and the `j`th wizard **cannot start working too early**.mark-detail -5. Write a program and print the `dp` array. If it is not as expected, adjust it. What did you find? - - As a result, you find that some values are smaller than expected. At this time, you need to think about whether there is a logical loophole based on those "abnormal" values. Where is the loophole? - mark-detail The logical loophole is: some wizards still start working too early, causing the potion to wait for people. mark-detail - - How to fix the logic loophole? - mark-detail **Process again from the back to the front**, because the last wizard no longer has the problem of starting work too early. This shows the importance of traversal order. It may be from front to back, or from back to front, or both. mark-detail - -## Complexity - -- Time complexity: `O(M * N)`. -- Space complexity: `O(N)`. - -## Ruby - -```ruby -# It may fail, but its not the problem of algorithm because same code can be accepted in other languages -# @param {Integer[]} skill -# @param {Integer[]} mana -# @return {Integer} -def min_time(skill, mana) - n = skill.size - m = mana.size - dp = Array.new(n, 0) - - m.times do |i| - n.times do |j| - dp[j] = [dp[j], dp[j - 1]].max if j >= 1 # condition 1 and 2 - time_consuming = mana[i] * skill[j] - dp[j] = [dp[j], dp[j + 1] - time_consuming].max if j < n - 1 # condition 3 - dp[j] += time_consuming - end - - # Process again from back to front to prevent any wizard from starting work too early. - (1...n).to_a.reverse.each do |j| - dp[j - 1] = dp[j] - mana[i] * skill[j] - end - end - - dp[-1] -end -``` - -## Python - -```python -# It may fail, but its not the problem of algorithm because same code can be accepted in other languages -class Solution: - def minTime(self, skill: List[int], mana: List[int]) -> int: - n = len(skill) - m = len(mana) - dp = [0] * n - - for i in range(m): - for j in range(n): - # condition 1 and 2 - if j >= 1: - dp[j] = max(dp[j], dp[j - 1]) - - time_consuming = mana[i] * skill[j] - - # condition 3 - if j < n - 1: - dp[j] = max(dp[j], dp[j + 1] - time_consuming) - dp[j] += time_consuming - - # Process again from back to front to prevent any wizard from starting work too early. - for j in range(n - 1, 0, -1): - dp[j - 1] = dp[j] - mana[i] * skill[j] - - return dp[-1] -``` - -## JavaScript - -```javascript -/** - * @param {number[]} skill - * @param {number[]} mana - * @return {number} - */ -var minTime = function (skill, mana) { - const n = skill.length; - const m = mana.length; - const dp = new Array(n).fill(0); - - for (let i = 0; i < m; i++) { - for (let j = 0; j < n; j++) { - // condition 1 and 2 - if (j >= 1) { - dp[j] = Math.max(dp[j], dp[j - 1]); - } - const timeConsuming = mana[i] * skill[j]; - // condition 3 - if (j < n - 1) { - dp[j] = Math.max(dp[j], dp[j + 1] - timeConsuming); - } - dp[j] += timeConsuming; - } - - // Process again from back to front to prevent any wizard from starting work too early. - for (let j = n - 1; j > 0; j--) { - dp[j - 1] = dp[j] - mana[i] * skill[j]; - } - } - - return dp[dp.length - 1]; -}; -``` - -## Java - -```java -class Solution { - public long minTime(int[] skill, int[] mana) { - int n = skill.length; - int m = mana.length; - long[] dp = new long[n]; - - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // condition 1 and 2 - if (j >= 1) { - dp[j] = Math.max(dp[j], dp[j - 1]); - } - long timeConsuming = (long) mana[i] * skill[j]; - // condition 3 - if (j < n - 1) { - dp[j] = Math.max(dp[j], dp[j + 1] - timeConsuming); - } - dp[j] += timeConsuming; - } - - // Process again from back to front to prevent any wizard from starting work too - // early - for (int j = n - 1; j > 0; j--) { - dp[j - 1] = dp[j] - (long) mana[i] * skill[j]; - } - } - - return dp[n - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public long MinTime(int[] skill, int[] mana) - { - int n = skill.Length; - int m = mana.Length; - long[] dp = new long[n]; - - for (int i = 0; i < m; i++) - { - for (int j = 0; j < n; j++) - { - // condition 1 and 2 - if (j >= 1) - { - dp[j] = Math.Max(dp[j], dp[j - 1]); - } - long timeConsuming = (long)mana[i] * skill[j]; - // condition 3 - if (j < n - 1) - { - dp[j] = Math.Max(dp[j], dp[j + 1] - timeConsuming); - } - dp[j] += timeConsuming; - } - - // Process again from back to front to prevent any wizard from starting work too early - for (int j = n - 1; j > 0; j--) - { - dp[j - 1] = dp[j] - (long)mana[i] * skill[j]; - } - } - - return dp[n - 1]; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - long long minTime(vector& skill, vector& mana) { - int n = skill.size(); - int m = mana.size(); - vector dp(n, 0); - - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // condition 1 and 2 - if (j >= 1) { - dp[j] = max(dp[j], dp[j - 1]); - } - long long time_consuming = (long long)mana[i] * skill[j]; - // condition 3 - if (j < n - 1) { - dp[j] = max(dp[j], dp[j + 1] - time_consuming); - } - dp[j] += time_consuming; - } - - // Process again from back to front to prevent any wizard from - // starting work too early - for (int j = n - 1; j > 0; j--) { - dp[j - 1] = dp[j] - (long long)mana[i] * skill[j]; - } - } - - return dp[n - 1]; - } -}; -``` - -## Go - -```go -func minTime(skill []int, mana []int) int64 { - n := len(skill) - m := len(mana) - dp := make([]int64, n) - - for i := 0; i < m; i++ { - for j := 0; j < n; j++ { - // condition 1 and 2 - if j >= 1 && dp[j-1] > dp[j] { - dp[j] = dp[j-1] - } - timeConsuming := int64(mana[i]) * int64(skill[j]) - // condition 3 - if j < n-1 { - if dp[j+1]-timeConsuming > dp[j] { - dp[j] = dp[j+1] - timeConsuming - } - } - dp[j] += timeConsuming - } - - // Process again from back to front to prevent any wizard from starting work too early - for j := n - 1; j > 0; j-- { - dp[j-1] = dp[j] - int64(mana[i])*int64(skill[j]) - } - } - - return dp[n-1] -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.blog](https://leetcode.blog): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! - -Original link: [3494. Find the Minimum Amount of Time to Brew Potions - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.blog/en/leetcode/3494-find-the-minimum-amount-of-time-to-brew-potions). - -GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/en/3001-4000/unorganized.md b/en/3001-4000/unorganized.md deleted file mode 100644 index 971b4e5..0000000 --- a/en/3001-4000/unorganized.md +++ /dev/null @@ -1,267 +0,0 @@ -# LeetCode skills -If you want to solve problems in the most understandable way, please look for Coding5DotCom. - -## Array -* Array is consecutive in memory. -* Cannot delete an item. Actually, it is overwrite. Delete a item of array will call the latter items move 1 to left. So it is `O(n)` time complexity. -* C++ 2D array is also consecutive. But Java is not. - -## Hash function -You want to store students' information into a hash table. -You want to query information by a student's name. -* `index = theHashFunction(student_name)` `the_information = the_hash_table[index]`. - -## Binary tree unified stack iteration -`boolean mark` solution. - -## Other Algorithms -### Recursion -* Recursion steps: - 1. Determine the parameters - 2. Determine the recursion logic - 3. Determine the return value - 4. Determine the exit logic - -## Dynamic programming -- [647. Palindromic Substrings](https://leetcode.cn/problems/palindromic-substrings/) -- [516. Longest Palindromic Subsequence](https://leetcode.cn/problems/longest-palindromic-subsequence/) -For solving the above two issues, we can use two-dimensional array. Remember the `magic word`: **回文串,用一半,内环反**. - -The principle of `dynamic programming` is **from top to bottom, from left to right, from less to more, from near to far, from known to unknown** -and **take turns being the boss**. - -## Monotonic stack -* Push indies one by one. -* Only the useful indies are kept in the stack. Useless indices are popped (or eaten by followed larger (or smaller) index). - -## Graph theory -The principle of traversal (DFS or BFS) between `undirected graph` or `directed graph` are similar. -* First rule: don't visited nodes again. This rule make starting from a node to traverse the `undirected graph` have a direction. -* The adjacent nodes of `undirected graph` are its non-visited neighbors. -* The adjacent nodes of `directed graph` are its targeted nodes. - -* Truth: An `undirected graph` can be understood as a **bidirectional** `directed graph`. Sometimes, we make use of it. - -### Minimum spanning a tree -* `Prim's algorithm` can be used to minimum spanning a tree. It added the closest node to the tree each time. It uses a `min_distances`. It is recommended to use a `priority_queue`. -* `Kruskal's algorithm` can also be used to minimum spanning a tree, but it adds the shortest edge each time. To combine the two nodes of an edge, `UnionFind` is used. - -### Shortest path -* This is graph, not a tree. It can have cycles and many connected components. -* `Dijkstra's algorithm` finds the shortest path from one vertex to all other vertices. It is like `Prim's algorithm`, also uses a `min_distances`, but the distance is to the original `source` vertex. All the weights of edges **must not be a negative value**. -* `Bellman_Ford algorithm` finds the shortest path from one vertex to all other vertices. It effectively works in the cases of **negative edges** and is able to **detect negative weight cycles**. -It also uses `min_distances`. Relaxation works by continuously shortening the calculated distance. It's straightforward and easily to be coded. -The improved way with a queue is commonly more efficient. Relaxing **All Edges** by `vertices.length – 1` times gives us _Single Source Shortest Path_ to all vertices. -* `Bellman_Ford algorithm` need to start from **one source** vertex each time and find the shortest paths to the source vertex. `Floyd–Warshall algorithm` can find all vertices' shortest paths. -* What `Floyd–Warshall algorithm` solves can also be done by iterating through `vertices` and apply `Bellman_Ford algorithm` on each vertex; But if it is a `Dense Graph`, `Floyd–Warshall algorithm` is faster. -* If all edges' weights are not negative, what `Floyd–Warshall algorithm` solves can also be done by iterating through `vertices` and apply `Dijkstra algorithm` on each vertex. -* The time complexity of running V times `Dijkstra algorithm` is `E * logE * V`. -* The time complexity of `Floyd–Warshall algorithm` is `V * V * V`. For a dense graph, `Floyd–Warshall algorithm` is still faster. -* `A* algorithm` use a `priority queue`, `pop()` to get the vertex closest to the destination vertex. We need to choose **proper math formula** to determine which one is the closest. We to the very near place of destination vertex, we can use some special method to make it can handle the last part. - -|Algorithm name|Focus|Key implementation methods|mark visited| -|Prim's algorithm|Vertices|| -|Kruskal's algorithm|Edges|Union-Find| -|Dijkstra's algorithm|Vertices|| -|Bellman-Ford algorithm|Edges(Vertices+Edges for SPFA)|| -|Dijkstra's by heap sort - min_distance = A*| -UnionFind + Heap sort = Kruskal -BFS + heap sort = A* - -Add a table to show the differences between A-Start and breadth-first search - -## Others -* Find all the prime numbers within 1000000. - -## Solutions which need a perfection -- 583 https://leetcode.cn/problems/delete-operation-for-two-strings/ would be better use https://leetcode.cn/problems/delete-operation-for-two-strings/submissions/597725071/ as the first option. - -## Skipped problems/solutions -- 704 Binary Search Algorithm -- 27 Fast and Slow Pointers - -- 1047 https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/ -- 150 https://leetcode.cn/problems/evaluate-reverse-polish-notation/ -- 239 https://leetcode.cn/problems/sliding-window-maximum/ tag `monotonic queue` -- 347 https://leetcode.cn/problems/top-k-frequent-elements/ tag `heap sort` - -### Binary Tree -* Remember to add the recursion steps (described above in this doc) first - -- 144 https://leetcode.cn/problems/binary-tree-preorder-traversal/ -- 94 https://leetcode.cn/problems/binary-tree-inorder-traversal/ -- 145 https://leetcode.cn/problems/binary-tree-postorder-traversal/ -- 102 https://leetcode.cn/problems/binary-tree-level-order-traversal/ - - 107 https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/ - - 199 https://leetcode.cn/problems/binary-tree-right-side-view/ - - 637 https://leetcode.cn/problems/average-of-levels-in-binary-tree/ - - 429 https://leetcode.cn/problems/n-ary-tree-level-order-traversal/ - - 515 https://leetcode.cn/problems/find-largest-value-in-each-tree-row/ - - 116 https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/ - - 117 https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/ - - 111 https://leetcode.cn/problems/minimum-depth-of-binary-tree/ - - 513 https://leetcode.cn/problems/find-bottom-left-tree-value - -- 104 https://leetcode.cn/problems/maximum-depth-of-binary-tree/ -- 226 https://leetcode.cn/problems/invert-binary-tree/ -- 101 https://leetcode.cn/problems/symmetric-tree/ - - 100 https://leetcode.cn/problems/same-tree/description/ - - 572 https://leetcode.cn/problems/subtree-of-another-tree/ - -- 222 https://leetcode.cn/problems/count-complete-tree-nodes/ -- 110 https://leetcode.cn/problems/balanced-binary-tree/ 2 ways -- 257 https://leetcode.cn/problems/binary-tree-paths/ -- 404 https://leetcode.cn/problems/sum-of-left-leaves/ -- 112 https://leetcode.cn/problems/path-sum/ -- 105 https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ -- 106 https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/ -- 654 https://leetcode.cn/problems/maximum-binary-tree/ -- 617 https://leetcode.cn/problems/merge-two-binary-trees/ -- 700 https://leetcode.cn/problems/search-in-a-binary-search-tree/ -- 530 https://leetcode.cn/problems/minimum-absolute-difference-in-bst/ - 783 https://leetcode.com/problems/minimum-distance-between-bst-nodes/ is the same -- 501 https://leetcode.cn/problems/find-mode-in-binary-search-tree/ -- 701 https://leetcode.cn/problems/insert-into-a-binary-search-tree/ Carl's solution is shorter, but may hard to understand and think about -- 450 https://leetcode.cn/problems/delete-node-in-a-bst/ Carl's solution is shorter -- 669 https://leetcode.cn/problems/trim-a-binary-search-tree/description/ -- 108 https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/ -- 538 https://leetcode.cn/problems/convert-bst-to-greater-tree/ - -### Backtracking -- 77 https://leetcode.cn/problems/combinations/ -- 216 https://leetcode.cn/problems/combination-sum-iii/ -- 39 https://leetcode.cn/problems/combination-sum/ -- 17 https://leetcode.cn/problems/letter-combinations-of-a-phone-number/ -- 78 https://leetcode.cn/problems/subsets/ -- 90 https://leetcode.cn/problems/subsets-ii/ -- 40 https://leetcode.cn/problems/combination-sum-ii/ -- 131 https://leetcode.cn/problems/palindrome-partitioning/ -- 93 https://leetcode.cn/problems/restore-ip-addresses/ -- 491 https://leetcode.cn/problems/non-decreasing-subsequences/ -- 46 https://leetcode.cn/problems/permutations/ -- 332 https://leetcode.cn/problems/reconstruct-itinerary/ -- 51 https://leetcode.cn/problems/n-queens/ - -### Greedy Algorithm -- 455 https://leetcode.cn/problems/assign-cookies/ -- 376 https://leetcode.cn/problems/wiggle-subsequence/ -- 53 https://leetcode.cn/problems/maximum-subarray/ -- 122 https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/ -- 55 https://leetcode.cn/problems/jump-game/ -- 45 https://leetcode.cn/problems/jump-game-ii/ -- 1005 https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/ -- 135 https://leetcode.cn/problems/candy/ -- 860 https://leetcode.cn/problems/lemonade-change/ -- 406 https://leetcode.cn/problems/queue-reconstruction-by-height/ -- 452 https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons -- 435 https://leetcode.cn/problems/non-overlapping-intervals/ -- 763 https://leetcode.cn/problems/partition-labels/ -- 56 https://leetcode.cn/problems/merge-intervals/ -- 738 https://leetcode.cn/problems/monotone-increasing-digits/ -- 968 https://leetcode.cn/problems/binary-tree-cameras/ - -### Dynamic programming -- 70 https://leetcode.cn/problems/climbing-stairs/ -- 746 https://leetcode.cn/problems/min-cost-climbing-stairs/ -- 62 https://leetcode.cn/problems/unique-paths/ -- 63 https://leetcode.cn/problems/unique-paths-ii/ -- 343 https://leetcode.cn/problems/integer-break/ -- 115 https://leetcode.cn/problems/distinct-subsequences/ - -#### backpack problems -- 279 https://leetcode.cn/problems/perfect-squares/ can have solution 2 - -#### palindrome issue key: from middle, 2-d, +1 or +2, dp.size = len(s), do it on left-bottom side. -- 647 https://leetcode.cn/problems/palindromic-substrings/ very hard -- 516 https://leetcode.cn/problems/longest-palindromic-subsequence/ - -### Graph -- 417 https://leetcode.com/problems/pacific-atlantic-water-flow/ -- 399 https://leetcode.com/problems/evaluate-division/ union-find -- 1976 https://leetcode.com/problems/number-of-ways-to-arrive-at-destination/ both use Dijkstra or Bellman-Ford can solve it. -- 1263 https://leetcode.com/problems/minimum-moves-to-move-a-box-to-their-target-location/ A-star -- 695. Max Area of Island 2 other ways should be added with code -- 827 making-a-large-island breadth-first-search should be added with code - -### Failed in 2 rounds -- 222 https://leetcode.cn/problems/count-complete-tree-nodes/ -- 236 https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/ -- 40 https://leetcode.cn/problems/combination-sum-ii/ -- 131 https://leetcode.cn/problems/palindrome-partitioning/ -- 332 https://leetcode.cn/problems/reconstruct-itinerary/ -- 51 https://leetcode.cn/problems/n-queens/ -- 37 https://leetcode.cn/problems/sudoku-solver -- 96 https://leetcode.cn/problems/unique-binary-search-trees/ Finished but slow. -- 115 https://leetcode.cn/problems/distinct-subsequences/ -- 647 https://leetcode.cn/problems/palindromic-substrings/ https://leetcode.cn/problems/palindromic-substrings/submissions/597748845/ -- 516 https://leetcode.cn/problems/longest-palindromic-subsequence/ -- 417 https://leetcode.com/problems/pacific-atlantic-water-flow/ -- 1584-min-cost-to-connect-all-points-2.md -- 1514-path-with-maximum-probability.md -- 1334 https://leetcode.com/problems/find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance -- 752 a star Add A* for 127? -- 3464 https://leetcode.cn/problems/maximize-the-distance-between-points-on-a-square -- https://leetcode.cn/problems/closest-equal-element-queries/ -- https://leetcode.cn/problems/rotate-array - -## other finished problems -- https://leetcode.com/problems/k-closest-points-to-origin/ -- https://leetcode.com/problems/find-special-substring-of-length-k/ -- https://leetcode.cn/problems/eat-pizzas/ -- https://leetcode.cn/problems/merge-intervals/ -- https://leetcode.cn/problems/longest-consecutive-sequence -- https://leetcode.cn/problems/container-with-most-water -- https://leetcode.cn/problems/longest-substring-without-repeating-characters -- https://leetcode.cn/problems/product-of-array-except-self/ -- https://leetcode.cn/problems/set-matrix-zeroes/ -- https://leetcode.cn/problems/copy-list-with-random-pointer/ -- https://leetcode.cn/problems/sort-list/ -- https://leetcode.cn/problems/maximum-depth-of-binary-tree/ -- https://leetcode.cn/problems/invert-binary-tree/ -- https://leetcode.cn/problems/symmetric-tree/ -- https://leetcode.cn/problems/binary-tree-level-order-traversal -- https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree -- https://leetcode.cn/problems/validate-binary-search-tree -- https://leetcode.cn/problems/kth-smallest-element-in-a-bst -- https://leetcode.cn/problems/binary-tree-right-side-view/ -- https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/ -- https://leetcode.cn/problems/positions-of-large-groups/ -- https://leetcode.cn/problems/masking-personal-information -- https://leetcode.cn/problems/flipping-an-image/ -- https://leetcode.cn/contest/weekly-contest-442/problems/maximum-containers-on-a-ship -- - -## Other algorithm -* 线段树 https://leetcode.cn/problems/fruits-into-baskets-iii - - - - -https://leetcode.cn/problems/closest-equal-element-queries -# Timeout1 -# class Solution: -# def solveQueries(self, nums: List[int], queries: List[int]) -> List[int]: -# n = len(nums) -# answer = [] -# -# for i in range(len(queries)): -# index = queries[i] -# num = nums[index] -# -# k = 1 -# -# while k < n: -# if num == nums[(index + k) % n]: -# answer.append(k) -# break -# -# if num == nums[index - k]: -# answer.append(k) -# break -# -# k += 1 -# -# if k == n: -# answer.append(-1) -# -# return answer diff --git a/images/127.png b/images/127.png deleted file mode 100644 index 7b189e7..0000000 Binary files a/images/127.png and /dev/null differ diff --git a/images/42.png b/images/42.png deleted file mode 100644 index a5f10c8..0000000 Binary files a/images/42.png and /dev/null differ diff --git a/images/684.png b/images/684.png deleted file mode 100644 index 9363510..0000000 Binary files a/images/684.png and /dev/null differ diff --git a/images/binary_tree_BFS_1.gif b/images/binary_tree_BFS_1.gif deleted file mode 100644 index d8fe07c..0000000 Binary files a/images/binary_tree_BFS_1.gif and /dev/null differ diff --git a/images/binary_tree_DFS_1.png b/images/binary_tree_DFS_1.png deleted file mode 100644 index 5ac8099..0000000 Binary files a/images/binary_tree_DFS_1.png and /dev/null differ diff --git a/images/examples/1334_1.png b/images/examples/1334_1.png deleted file mode 100644 index a9de4da..0000000 Binary files a/images/examples/1334_1.png and /dev/null differ diff --git a/images/examples/1334_2.png b/images/examples/1334_2.png deleted file mode 100644 index a12994b..0000000 Binary files a/images/examples/1334_2.png and /dev/null differ diff --git a/images/examples/144_1.png b/images/examples/144_1.png deleted file mode 100644 index 2f2aa00..0000000 Binary files a/images/examples/144_1.png and /dev/null differ diff --git a/images/examples/144_2.png b/images/examples/144_2.png deleted file mode 100644 index 94d68f6..0000000 Binary files a/images/examples/144_2.png and /dev/null differ diff --git a/images/examples/1514_1.png b/images/examples/1514_1.png deleted file mode 100644 index bf7705f..0000000 Binary files a/images/examples/1514_1.png and /dev/null differ diff --git a/images/examples/1514_2.png b/images/examples/1514_2.png deleted file mode 100644 index 89b1fc9..0000000 Binary files a/images/examples/1514_2.png and /dev/null differ diff --git a/images/examples/1514_3.png b/images/examples/1514_3.png deleted file mode 100644 index a978906..0000000 Binary files a/images/examples/1514_3.png and /dev/null differ diff --git a/images/examples/1584_1_1.png b/images/examples/1584_1_1.png deleted file mode 100644 index e11160d..0000000 Binary files a/images/examples/1584_1_1.png and /dev/null differ diff --git a/images/examples/1584_1_2.png b/images/examples/1584_1_2.png deleted file mode 100644 index 682772d..0000000 Binary files a/images/examples/1584_1_2.png and /dev/null differ diff --git a/images/examples/160.png b/images/examples/160.png deleted file mode 100644 index 55870e3..0000000 Binary files a/images/examples/160.png and /dev/null differ diff --git a/images/examples/160_1.png b/images/examples/160_1.png deleted file mode 100644 index e3bc868..0000000 Binary files a/images/examples/160_1.png and /dev/null differ diff --git a/images/examples/160_2.png b/images/examples/160_2.png deleted file mode 100644 index 947d989..0000000 Binary files a/images/examples/160_2.png and /dev/null differ diff --git a/images/examples/160_3.png b/images/examples/160_3.png deleted file mode 100644 index eea0631..0000000 Binary files a/images/examples/160_3.png and /dev/null differ diff --git a/images/examples/1971_1.png b/images/examples/1971_1.png deleted file mode 100644 index 5f149cf..0000000 Binary files a/images/examples/1971_1.png and /dev/null differ diff --git a/images/examples/1971_2.png b/images/examples/1971_2.png deleted file mode 100644 index 6461b4f..0000000 Binary files a/images/examples/1971_2.png and /dev/null differ diff --git a/images/examples/19_1.jpg b/images/examples/19_1.jpg deleted file mode 100644 index 1e76e1d..0000000 Binary files a/images/examples/19_1.jpg and /dev/null differ diff --git a/images/examples/203_1.jpg b/images/examples/203_1.jpg deleted file mode 100644 index 5f5f84d..0000000 Binary files a/images/examples/203_1.jpg and /dev/null differ diff --git a/images/examples/206_1.jpg b/images/examples/206_1.jpg deleted file mode 100644 index 697bf93..0000000 Binary files a/images/examples/206_1.jpg and /dev/null differ diff --git a/images/examples/206_2.jpg b/images/examples/206_2.jpg deleted file mode 100644 index a50261a..0000000 Binary files a/images/examples/206_2.jpg and /dev/null differ diff --git a/images/examples/24_1.jpg b/images/examples/24_1.jpg deleted file mode 100644 index 34d20ce..0000000 Binary files a/images/examples/24_1.jpg and /dev/null differ diff --git a/images/examples/27_hint_2.png b/images/examples/27_hint_2.png deleted file mode 100644 index 9adef03..0000000 Binary files a/images/examples/27_hint_2.png and /dev/null differ diff --git a/images/examples/42_1.png b/images/examples/42_1.png deleted file mode 100644 index 578e81e..0000000 Binary files a/images/examples/42_1.png and /dev/null differ diff --git a/images/examples/463_1.png b/images/examples/463_1.png deleted file mode 100644 index 76254a7..0000000 Binary files a/images/examples/463_1.png and /dev/null differ diff --git a/images/examples/59_1.jpg b/images/examples/59_1.jpg deleted file mode 100644 index 25564dd..0000000 Binary files a/images/examples/59_1.jpg and /dev/null differ diff --git a/images/examples/684_1.jpg b/images/examples/684_1.jpg deleted file mode 100644 index 5baf163..0000000 Binary files a/images/examples/684_1.jpg and /dev/null differ diff --git a/images/examples/684_2.jpg b/images/examples/684_2.jpg deleted file mode 100644 index 72d7291..0000000 Binary files a/images/examples/684_2.jpg and /dev/null differ diff --git a/images/examples/685_1.jpg b/images/examples/685_1.jpg deleted file mode 100644 index 1f9ebd6..0000000 Binary files a/images/examples/685_1.jpg and /dev/null differ diff --git a/images/examples/685_2.jpg b/images/examples/685_2.jpg deleted file mode 100644 index f4fc940..0000000 Binary files a/images/examples/685_2.jpg and /dev/null differ diff --git a/images/examples/695_1.jpg b/images/examples/695_1.jpg deleted file mode 100644 index 127b540..0000000 Binary files a/images/examples/695_1.jpg and /dev/null differ diff --git a/images/examples/743_1.png b/images/examples/743_1.png deleted file mode 100644 index 3b07d83..0000000 Binary files a/images/examples/743_1.png and /dev/null differ diff --git a/images/examples/787_1.png b/images/examples/787_1.png deleted file mode 100644 index 3cd965e..0000000 Binary files a/images/examples/787_1.png and /dev/null differ diff --git a/images/examples/787_2.png b/images/examples/787_2.png deleted file mode 100644 index 7992cac..0000000 Binary files a/images/examples/787_2.png and /dev/null differ diff --git a/images/examples/787_3.png b/images/examples/787_3.png deleted file mode 100644 index 661b292..0000000 Binary files a/images/examples/787_3.png and /dev/null differ diff --git a/images/examples/797_1.jpg b/images/examples/797_1.jpg deleted file mode 100644 index 5c01a24..0000000 Binary files a/images/examples/797_1.jpg and /dev/null differ diff --git a/images/examples/797_2.jpg b/images/examples/797_2.jpg deleted file mode 100644 index d9cabcd..0000000 Binary files a/images/examples/797_2.jpg and /dev/null differ diff --git a/images/examples/833_1.png b/images/examples/833_1.png deleted file mode 100644 index 986a9a7..0000000 Binary files a/images/examples/833_1.png and /dev/null differ diff --git a/images/examples/833_2.png b/images/examples/833_2.png deleted file mode 100644 index 7eda6ca..0000000 Binary files a/images/examples/833_2.png and /dev/null differ diff --git a/images/examples/84_1.jpg b/images/examples/84_1.jpg deleted file mode 100644 index 3e9fc83..0000000 Binary files a/images/examples/84_1.jpg and /dev/null differ diff --git a/images/examples/84_2.jpg b/images/examples/84_2.jpg deleted file mode 100644 index 2d1e6d3..0000000 Binary files a/images/examples/84_2.jpg and /dev/null differ diff --git a/images/graph_Bellman-Ford_algorithm_animation.gif b/images/graph_Bellman-Ford_algorithm_animation.gif deleted file mode 100644 index d219304..0000000 Binary files a/images/graph_Bellman-Ford_algorithm_animation.gif and /dev/null differ diff --git a/images/graph_Dijkstra_algorithm_animation.gif b/images/graph_Dijkstra_algorithm_animation.gif deleted file mode 100644 index 3b1f8f7..0000000 Binary files a/images/graph_Dijkstra_algorithm_animation.gif and /dev/null differ diff --git a/images/graph_tree_1.png b/images/graph_tree_1.png deleted file mode 100644 index 470cfd2..0000000 Binary files a/images/graph_tree_1.png and /dev/null differ diff --git a/images/graph_undirected_1.svg b/images/graph_undirected_1.svg deleted file mode 100644 index 68bd093..0000000 --- a/images/graph_undirected_1.svg +++ /dev/null @@ -1,74 +0,0 @@ - - -]> - - - - -untitled - - -1 - -1 - - -2 - -2 - - -1--2 - - - -3 - -3 - - -2--3 - - - -5 - -5 - - -2--5 - - - -4 - -4 - - -3--4 - - - -4--5 - - - -5--1 - - - -6 - -6 - - -6--4 - - - - diff --git a/images/graph_undirected_2.png b/images/graph_undirected_2.png deleted file mode 100644 index f488e42..0000000 Binary files a/images/graph_undirected_2.png and /dev/null differ diff --git a/images/hints/27_2.png b/images/hints/27_2.png deleted file mode 100644 index 9adef03..0000000 Binary files a/images/hints/27_2.png and /dev/null differ diff --git a/zh/1-1000/1-two-sum.md b/zh/1-1000/1-two-sum.md deleted file mode 100644 index 3979d38..0000000 --- a/zh/1-1000/1-two-sum.md +++ /dev/null @@ -1,330 +0,0 @@ -# 1. 两数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[1. 两数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1-two-sum),体验更佳! - -力扣链接:[1. 两数之和](https://leetcode.cn/problems/two-sum), 难度等级:**简单**。 - -## LeetCode “1. 两数之和”问题描述 - -给定一个整数数组 `nums` 和一个整数目标值 `target`,请你在该数组中找出 **和为目标值** `target` 的那 **两个** 整数,并返回它们的数组下标。 - -你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。 - -你可以按任意顺序返回答案。 - -### [示例 1] - -**输入**: `nums = [2,7,11,15], target = 9` - -**输出**: `[0,1]` - -**解释**: `因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。` - -### [示例 2] - -**输入**: `nums = [3,2,4], target = 6` - -**输出**: `[1,2]` - -### [示例 3] - -**输入**: `nums = [3,3], target = 6` - -**输出**: `[0,1]` - -### [约束] - -- `2 <= nums.length <= 10^4` -- `-10^9 <= nums[i] <= 10^9` -- `-10^9 <= target <= 10^9` -- **只会存在一个有效答案** - -### [Hints] - -
- 提示 1 - A really brute force way would be to search for all possible pairs of numbers but that would be too slow. Again, it's best to try out brute force solutions for just for completeness. It is from these brute force solutions that you can come up with optimizations. - - -
- -
- 提示 2 - So, if we fix one of the numbers, say `x`, we have to scan the entire array to find the next number `y` which is `value - x` where value is the input parameter. Can we change our array somehow so that this search becomes faster? - - -
- -
- 提示 3 - The second train of thought is, without changing the array, can we use additional space somehow? Like maybe a hash map to speed up the search? - - -
- -## 思路 1 - -1. 暴力解法的时间复杂度为`O(n**2)`,想提升效率,可以对数组进行排序,然后用双指针,一个指向数组头,一个指向数组尾,根据**和**情况决定`left += 1`还是`right -= 1`。 - -2. 对数值数组排序后,想知道某个数值对应的原来的索引下标,有两种方案: - -
点击查看答案

- - - 方案1:在排序时带上索引下标,即排序的对象是元组`(num, index)`的数组。这个技术**一定要掌握**,许多题目都会用到。 - - 方案2:使用index() 查找,已经放到另外一个题解中讲解。 -

- -## 复杂度 - -- 时间复杂度: `O(N * log N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - num_index_list = [(num, i) for i, num in enumerate(nums)] - num_index_list.sort() - - left = 0 - right = len(nums) - 1 - - while left < right: - sum_ = num_index_list[left][0] + num_index_list[right][0] - - if sum_ == target: - return [num_index_list[left][1], num_index_list[right][1]] - - if sum_ < target: - left += 1 - continue - - right -= 1 -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -1. `Map`中,`key`是`num`,`value`是数组`index`。 -2. 遍历数组,如果`target - num`在`Map`中,返回。反之,将`num`加入`Map`中。 - -## 步骤 - -1. `Map`中,`key`是`num`,`value`是数组`index`。 - - ```javascript - let numToIndex = new Map() - - for (let i = 0; i < nums.length; i++) { - numToIndex.set(nums[i], i) - } - ``` - -2. 遍历数组,如果`target - num`在`Map`中,返回。反之,将`num`加入`Map`中。 - - ```javascript - let numToIndex = new Map() - - for (let i = 0; i < nums.length; i++) { - if (numToIndex.has(target - nums[i])) { // 1 - return [numToIndex.get(target - nums[i]), i] // 2 - } - - numToIndex.set(nums[i], i) - } - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public int[] twoSum(int[] nums, int target) { - var numToIndex = new HashMap(); - - for (var i = 0; i < nums.length; i++) { - if (numToIndex.containsKey(target - nums[i])) { - return new int[]{numToIndex.get(target - nums[i]), i}; - } - - numToIndex.put(nums[i], i); - } - - return null; - } -} -``` - -## Python - -```python -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - num_to_index = {} - - for i, num in enumerate(nums): - if target - num in num_to_index: - return [num_to_index[target - num], i] - - num_to_index[num] = i -``` - -## C++ - -```cpp -class Solution { -public: - vector twoSum(vector& nums, int target) { - unordered_map num_to_index; - - for (auto i = 0; i < nums.size(); i++) { - if (num_to_index.contains(target - nums[i])) { - return {num_to_index[target - nums[i]], i}; - } - - num_to_index[nums[i]] = i; - } - - return {}; - } -}; -``` - -## JavaScript - -```javascript -var twoSum = function (nums, target) { - let numToIndex = new Map() - - for (let i = 0; i < nums.length; i++) { - if (numToIndex.has(target - nums[i])) { - return [numToIndex.get(target - nums[i]), i] - } - - numToIndex.set(nums[i], i) - } -}; -``` - -## C# - -```csharp -public class Solution { - public int[] TwoSum(int[] nums, int target) { - var numToIndex = new Dictionary(); - - for (int i = 0; i < nums.Length; i++) { - if (numToIndex.ContainsKey(target - nums[i])) { - return [numToIndex[target - nums[i]], i]; - } - - numToIndex[nums[i]] = i; - } - - return null; - } -} -``` - -## Go - -```go -func twoSum(nums []int, target int) []int { - numToIndex := map[int]int{} - - for i, num := range nums { - if index, ok := numToIndex[target - num]; ok { - return []int{index, i} - } - - numToIndex[num] = i - } - - return nil -} -``` - -## Ruby - -```ruby -def two_sum(nums, target) - num_to_index = {} - - nums.each_with_index do |num, i| - if num_to_index.key?(target - num) - return [num_to_index[target - num], i] - end - - num_to_index[num] = i - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 3 - -1. 暴力解法的时间复杂度为`O(n^2)`,想提升效率,可以对数组进行排序,然后用双指针,一个指向数组头,一个指向数组尾,根据**和**情况决定`left += 1`还是`right -= 1`。 -2. 找出了两个值后,需要用`index()`方法去找值对应的`index`。 - -## 复杂度 - -- 时间复杂度: `O(N * log N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - original_nums = nums.copy() - nums.sort() - - left = 0 - right = len(nums) - 1 - - while left < right: - sum_ = nums[left] + nums[right] - - if sum_ == target: - break - - if sum_ < target: - left += 1 - continue - - right -= 1 - - return [ - original_nums.index(nums[left]), - len(nums) - 1 - original_nums[::-1].index(nums[right]) - ] -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[1. 两数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1-two-sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/121-best-time-to-buy-and-sell-stock.md b/zh/1-1000/121-best-time-to-buy-and-sell-stock.md deleted file mode 100644 index 852c919..0000000 --- a/zh/1-1000/121-best-time-to-buy-and-sell-stock.md +++ /dev/null @@ -1,124 +0,0 @@ -# 121. Best Time to Buy and Sell Stock (Dynamic Programming Solution) -LeetCode link: [121. Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -You want to **maximize** your profit by choosing **a single day** to buy one stock and choosing **a different day** in the future to sell that stock. - -Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return `0`. - -### [Example 1] -**Input**: `prices = [7,1,5,3,6,4]` - -**Output**: `5` - -**Explanation** -``` -Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. -Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell. -``` - -### [Example 2] -**Input**: `prices = [7,6,4,3,1]` - -**Output**: `0` - -**Explanation**: `In this case, no transactions are done and the max profit = 0.` - -### [Constraints] -- `1 <= prices.length <= 100000` -- `0 <= prices[i] <= 10000` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - # states: - # 0: hold stock - # 1) keep holding - # 2) today just bought - # 1: no stock - # 1) keep no stock - # 2) today just sold - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], -price) - dp[1] = max(dc[1], dc[0] + price) - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices) { - const dp = [-prices[0], 0] - - for (let i = 1; i < prices.length; i++) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], -prices[i]) - dp[1] = Math.max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], -prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/122-best-time-to-buy-and-sell-stock-ii.md b/zh/1-1000/122-best-time-to-buy-and-sell-stock-ii.md deleted file mode 100644 index 222638a..0000000 --- a/zh/1-1000/122-best-time-to-buy-and-sell-stock-ii.md +++ /dev/null @@ -1,157 +0,0 @@ -# 122. Best Time to Buy and Sell Stock II (Dynamic Programming Solution) -LeetCode link: [122. Best Time to Buy and Sell Stock II](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) - -## LeetCode problem description -You are given an integer array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -On each day, you may decide to buy and/or sell the stock. You can only hold **at most one** share of the stock at any time. However, you can buy it then immediately sell it **on the same day**. - -Find and return the **maximum** profit you can achieve. - -``` ------------------------------------------------------------------------------------------------------------------------ -[Example 1] - -Input: prices = [7,1,5,3,6,4] -Output: 7 - -Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. -Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. -Total profit is 4 + 3 = 7. ------------------------------------------------------------------------------------------------------------------------ -[Example 2] - -Input: prices = [1,2,3,4,5] -Output: 4 - -Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. -Total profit is 4. ------------------------------------------------------------------------------------------------------------------------ -[Example 3] - -Input: prices = [7,6,4,3,1] -Output: 0 - -Explanation: There is no way to make a positive profit, so we never buy the stock to achieve the maximum profit of 0. ------------------------------------------------------------------------------------------------------------------------ -[Constraints] - -1 <= prices.length <= 3 * 10000 -0 <= prices[i] <= 10000 ------------------------------------------------------------------------------------------------------------------------ -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Solution 1 -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - # states: - # 0: hold stock - # 1) keep holding - # 2) today just bought - # 1: no stock - # 1) keep no stock - # 2) today just sold - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], dc[1] - price) - dp[1] = max(dc[1], dc[0] + price) - - return dp[1] -``` - -### Solution 2 -```python -class Solution: - # 0: have stock - # 1) just bought - # 2) keep holding - # 1: have no stock - # 1) just sold - # 2) keep no stock - def maxProfit(self, prices: List[int]) -> int: - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = -price - dp[1] = max(dc[1], dc[1] + dc[0] + price) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices) { - const dp = [-prices[0], 0] - - for (let i = 1; i < prices.length; i++) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], dc[1] - prices[i]) - dp[1] = Math.max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], dc[1] - prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i]) - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/123-best-time-to-buy-and-sell-stock-iii.md b/zh/1-1000/123-best-time-to-buy-and-sell-stock-iii.md deleted file mode 100644 index 111f681..0000000 --- a/zh/1-1000/123-best-time-to-buy-and-sell-stock-iii.md +++ /dev/null @@ -1,133 +0,0 @@ -# 123. Best Time to Buy and Sell Stock III (Dynamic Programming Solution) -LeetCode link: [122. Best Time to Buy and Sell Stock III](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -Find the **maximum** profit you can achieve. You may complete **at most two transactions**. - -**Note**: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). - -``` ------------------------------------------------------------------------------------------------------------------------ -[Example 1] - -Input: prices = [3,3,5,0,0,3,1,4] -Output: 6 - -Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3. -Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3. ------------------------------------------------------------------------------------------------------------------------ -[Example 2] - -Input: prices = [1,2,3,4,5] -Output: 4 - -Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. -Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again. ------------------------------------------------------------------------------------------------------------------------ -[Example 3] - -Input: prices = [7,6,4,3,1] -Output: 0 - -Explanation: In this case, no transaction is done, i.e. max profit = 0. ------------------------------------------------------------------------------------------------------------------------ -[Constraints] - -1 <= prices.length <= 100000 -0 <= prices[i] <= 100000 ------------------------------------------------------------------------------------------------------------------------ -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - dp = [-prices[0], 0, -prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], -price) - dp[1] = max(dc[1], dc[0] + price) - dp[2] = max(dc[2], dc[1] - price) - dp[3] = max(dc[3], dc[2] + price) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices) { - const dp = [-prices[0], 0, -prices[0], 0] - - for (const price of prices.slice(1,)) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], -price) - dp[1] = Math.max(dc[1], dc[0] + price) - dp[2] = Math.max(dc[2], dc[1] - price) - dp[3] = Math.max(dc[3], dc[2] + price) - } - - return dp[3] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0, -prices[0], 0} - - for _, price := range prices[1:] { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], -price) - dp[1] = max(dc[1], dc[0] + price) - dp[2] = max(dc[2], dc[1] - price) - dp[3] = max(dc[3], dc[2] + price) - } - - return dp[3] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/127-word-ladder.md b/zh/1-1000/127-word-ladder.md deleted file mode 100644 index c14099d..0000000 --- a/zh/1-1000/127-word-ladder.md +++ /dev/null @@ -1,164 +0,0 @@ -# LeetCode 127. Word Ladder's Solution -LeetCode link: [127. Word Ladder](https://leetcode.com/problems/word-ladder/) - -## LeetCode problem description -A **transformation sequence** from word `beginWord` to word `endWord` using a dictionary `wordList` is a sequence of words `beginWord -> s1 -> s2 -> ... -> sk` such that: - -* Every adjacent pair of words differs by a single letter. -* Every `si` for `1 <= i <= k` is in `wordList`. Note that `beginWord` does not need to be in `wordList`. -* `sk == endWord` - -Given two words, `beginWord` and `endWord`, and a dictionary `wordList`, return **the number of words** in the **shortest transformation sequence** from `beginWord` to `endWord`, or `0` if no such sequence exists. - -### Example 1 -``` -Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] -Output: 5 -Explanation: One shortest transformation sequence is "hit" -> "hot" -> "dot" -> "dog" -> cog", which is 5 words long. -``` - -### Example 2 -``` -Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"] -Output: 0 -Explanation: The endWord "cog" is not in wordList, therefore there is no valid transformation sequence. -``` - -### Constraints -- `1 <= beginWord.length <= 10` -- `endWord.length == beginWord.length` -- `1 <= wordList.length <= 5000` -- `wordList[i].length == beginWord.length` -- `beginWord`, `endWord`, and `wordList[i]` consist of lowercase English letters. -- `beginWord != endWord` -- All the words in `wordList` are **unique**. - -## Intuition -This problem is hard. Before solving this problem, you can do the following problem first: - -- [200. Number of Islands (Solution 3: Breadth-First Search)](200-number-of-islands-3.md) - -The **word transformation sequence** problem can be abstracted into a **graph theory** problem. And it is an **undirected graph**: - -![](../../images/127.png) - -### Breadth-First Search -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **breadth-first search** can be thought of as visiting vertices in rounds and rounds. Actually, whenever you see a question is about - getting `shortest` or `least` of something of a graph, `breadth-first search` would probably help. - -* `breadth-first search` emphasizes first-in-first-out, so a **queue** is needed. - -## Approach -1. `Breadth-First Search` a graph means traversing **from near to far**, from `circle 1` to `circle N`. Each `circle` is a round of iteration, but we can simplify it by using just 1 round. -1. So through `Breadth-First Search`, when a word matches `endWord`, the game is over, and we can return the number of **circle** as a result. - -## Complexity -* Time: `O((26 * end_word.length) * N)`. -* Space: `O(N)`. - -## Python -```python -from collections import deque - -class Solution: - def ladderLength(self, begin_word: str, end_word: str, word_list: List[str]) -> int: - words = set(word_list) - - if end_word not in words: - return 0 - - if begin_word == end_word: - return 1 - - queue = deque([begin_word]) - - if begin_word in words: - words.remove(begin_word) - - result = 0 - - while queue: - size = len(queue) - result += 1 - - for i in range(size): - current_word = queue.popleft() - - for word in one_letter_changed_words(current_word): - if word == end_word: - return result + 1 - - if word in words: - queue.append(word) - words.remove(word) - - return 0 - - -def one_letter_changed_words(word): - words = [] - - for i in range(len(word)): - for letter in 'abcdefghijklmnopqrstuvwxyz': - if letter != word[i]: - words.append(word[:i] + letter + word[i + 1:]) - - return words -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/139-word-break.md b/zh/1-1000/139-word-break.md deleted file mode 100644 index 9f17e96..0000000 --- a/zh/1-1000/139-word-break.md +++ /dev/null @@ -1,210 +0,0 @@ -# 139. Word Break -LeetCode link: [139. Word Break](https://leetcode.com/problems/word-break/) - -## LeetCode problem description -> Given a string `s` and a dictionary of strings `wordDict`, return `true` if `s` can be segmented into a space-separated sequence of one or more dictionary words. - -Note that the same word in the dictionary may be **reused multiple times** in the segmentation. - -``` ---------------------------------------------------------------------------------------------- -[Example 1] - -Input: s = "leetcode", wordDict = ["leet","code"] -Output: true -Explanation: Return true because "leetcode" can be segmented as "leet code". ---------------------------------------------------------------------------------------------- -[Example 2] - -Input: s = "applepenapple", wordDict = ["apple","pen"] -Output: true -Explanation: Return true because "applepenapple" can be segmented as "apple pen apple". - Note that you are allowed to reuse a dictionary word. ---------------------------------------------------------------------------------------------- -[Constraints] - -1 <= s.length <= 300 -1 <= wordDict.length <= 1000 -1 <= wordDict[i].length <= 20 -'s' and 'wordDict[i]' consist of only lowercase English letters. -All the strings of 'wordDict' are unique. ---------------------------------------------------------------------------------------------- -``` - -## Thoughts -This is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public bool WordBreak(string s, IList wordDict) - { - var dp = new bool[s.Length + 1]; - dp[0] = true; - - for (var i = 1; i < dp.Length; i++) - { - foreach (var word in wordDict) - { - if (dp[i]) - { - break; - } - - if (i >= word.Length) - { - dp[i] = dp[i - word.Length] && word == s[(i - word.Length)..i]; - } - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def wordBreak(self, s: str, wordDict: List[str]) -> bool: - dp = [False] * (len(s) + 1) - dp[0] = True - - for i in range(1, len(dp)): - for word in wordDict: - if dp[i]: - break - - if i >= len(word): - dp[i] = dp[i - len(word)] and word == s[i - len(word):i] - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - bool wordBreak(string s, vector& wordDict) { - auto dp = vector(s.size() + 1); - dp[0] = true; - - for (auto i = 1; i < dp.size(); i++) { - for (auto word : wordDict) { - if (dp[i]) { - break; - } - if (i >= word.size()) { - dp[i] = dp[i - word.size()] && - word == s.substr(i - word.size(), word.size()); - } - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public boolean wordBreak(String s, List wordDict) { - var dp = new boolean[s.length() + 1]; - dp[0] = true; - - for (var i = 1; i < dp.length; i++) { - for (var word : wordDict) { - if (dp[i]) { - break; - } - if (i >= word.length()) { - dp[i] = dp[i - word.length()] && - word.equals(s.substring(i - word.length(), i)); - } - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -``` -var wordBreak = function (s, wordDict) { - const dp = Array(s.length + 1).fill(false) - dp[0] = true - - for (let i = 1; i < dp.length; i++) { - for (const word of wordDict) { - if (dp[i]) { - break - } - if (i >= word.length) { - dp[i] = dp[i - word.length] && word == s.slice(i - word.length, i) - } - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func wordBreak(s string, wordDict []string) bool { - dp := make([]bool, len(s) + 1) - dp[0] = true - - for i := 1; i < len(dp); i++ { - for _, word := range wordDict { - if dp[i] { - break - } - if i >= len(word) { - dp[i] = dp[i - len(word)] && word == s[i - len(word):i] - } - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def word_break(s, word_dict) - dp = Array.new(s.size + 1, false) - dp[0] = true - - (1...dp.size).each do |i| - word_dict.each do |word| - break if dp[i] - - if i >= word.size - dp[i] = dp[i - word.size] && word == s[(i - word.size)...i] - end - end - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/144-binary-tree-preorder-traversal.md b/zh/1-1000/144-binary-tree-preorder-traversal.md deleted file mode 100644 index 32e7c9d..0000000 --- a/zh/1-1000/144-binary-tree-preorder-traversal.md +++ /dev/null @@ -1,137 +0,0 @@ -# 144. 二叉树的前序遍历 - 力扣题解最佳实践 -力扣链接:[144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal) ,难度:**容易**。 - -## 力扣“144. 二叉树的前序遍历”问题描述 -给你二叉树的根节点 `root` ,返回它节点值的 **前序** 遍历。 - -### [示例 1] - -**输入**: `root = [1,null,2,3]` - -**输出**: `[1,2,3]` - -**解释**: - -![](../../images/examples/144_1.png) - -### [示例 2] - -**输入**: `root = [1,2,3,4,5,null,8,null,null,6,7,9]` - -**输出**: `[1,2,4,5,6,7,3,8,9]` - -**解释**: - -![](../../images/examples/144_2.png) - -### [示例 3] - -**输入**: `root = []` - -**输出**: `[]` - -### [示例 4] - -**输入**: `root = [1]` - -**输出**: `[1]` - -### [约束] -- 树中节点数目在范围 `[0, 100]` 内 -- `-100 <= Node.val <= 100` - -## 思路 -以后会被添加。 - -## 步骤 -以后会被添加。 - -## 复杂度 -* 时间:`O(N)`。 -* 空间:`O(N)`。 - -## 进阶 -递归算法很简单,你可以通过迭代算法完成吗? - -## 进阶思路 -以后会被添加。 - -## Python -### Solution 1: Recursion -```python -class Solution: - def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: - self.values = [] - - self.traverse(root) - - return self.values - - def traverse(self, node): - if node is None: - return - - self.values.append(node.val) - - self.traverse(node.left) - - self.traverse(node.right) -``` - -### Solution 2: Iteration -```python -class Solution: - def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]: - values = [] - stack = [] - - if root: - stack.append(root) - - while stack: - node = stack.pop() - values.append(node.val) - - if node.right: - stack.append(node.right) - - if node.left: - stack.append(node.left) - - return values -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/15-3sum.md b/zh/1-1000/15-3sum.md deleted file mode 100644 index 7db6af4..0000000 --- a/zh/1-1000/15-3sum.md +++ /dev/null @@ -1,514 +0,0 @@ -# 15. 三数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[15. 三数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/15-3sum),体验更佳! - -力扣链接:[15. 三数之和](https://leetcode.cn/problems/3sum), 难度等级:**中等**。 - -## LeetCode “15. 三数之和”问题描述 - -给你一个整数数组 `nums` ,判断是否存在三元组 `[nums[i], nums[j], nums[k]]` 满足 `i != j`、`i != k` 且 `j != k` ,同时还满足 `nums[i] + nums[j] + nums[k] == 0` 。请你返回所有和为 `0` 且不重复的三元组。 - -**注意**:答案中**不**可以包含**重复**的三元组。 - - -### [示例 1] - -**输入**: `nums = [-1,0,1,2,-1,-4]` - -**输出**: `[[-1,-1,2],[-1,0,1]]` - -**解释**: - -

nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
-nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
-nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
-不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
-注意,输出的顺序和三元组的顺序并不重要。

- - -### [示例 2] - -**输入**: `nums = [0,1,1]` - -**输出**: `[]` - -**解释**: `唯一可能的三元组和不为 0 。` - -### [示例 3] - -**输入**: `nums = [0,0,0]` - -**输出**: `[[0,0,0]]` - -**解释**: `唯一可能的三元组和为 0 。` - -### [约束] - -- `3 <= nums.length <= 3000` -- `-10^5 <= nums[i] <= 10^5` - -### [Hints] - -
- 提示 1 - So, we essentially need to find three numbers `x`, `y`, and `z` such that they add up to the given value. If we fix one of the numbers say `x`, we are left with the two-sum problem at hand! - - -
- -
- 提示 2 - For the two-sum problem, if we fix one of the numbers, say `x`, we have to scan the entire array to find the next number `y`, which is `value - x` where value is the input parameter. Can we change our array somehow so that this search becomes faster? - - -
- -
- 提示 3 - The second train of thought for two-sum is, without changing the array, can we use additional space somehow? Like maybe a hash map to speed up the search? - - -
- -## 思路 1 - -1. 三个数相加等于0,等同于`两个数相加的和`等于`负的第三个数`。 -2. 有两种方案可供选择: - 1. 先定下一个数,然后查找另外两个数。 - 2. 先定下两个数,然后查找第三个数。 -3. 如果选择`方案2`,需要用到`Map`。因为需要对`nums`去重复;在`Map`中查找`第三个数`时,还需要避开已经定下的`两个数`,实现起来会比较麻烦。 -4. 如果选择`方案1`,查找另外两个数时,需要用到`双指针`算法。 -5. 对于`方案2`,仅给出了`Python`示例代码。下文重点讲`方案1`。 - -## 步骤 - -1. 对`nums`进行排序。 -2. 遍历`nums`。 -3. 伪代码: - - ```javascript - for (i = 0; i < nums.length; i++) { - left = i + 1 - right = nums.length - 1 - - while (left < right) { - if (condition1) { - left += 1 - } else (condition2) { - right -= 1 - } - } - } - ``` - -## 复杂度 - -- 时间复杂度: `O(N * N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -# If you want the program to run faster, uncomment the two places in the code. -class Solution: - def threeSum(self, nums: List[int]) -> List[List[int]]: - nums.sort() - # nums_2 = [] - # for i, num in enumerate(nums): - # if i >= 3 and num == nums[i - 1] == nums[i - 2] == nums[i - 3]: - # continue - # nums_2.append(num) - # nums = nums_2 - results = set() - - for i, num in enumerate(nums[:len(nums) - 2]): - # if num > 0: - # break - left = i + 1 - right = len(nums) - 1 - - while left < right: - sum_ = nums[left] + nums[right] - if sum_ == -num: - results.add((num, nums[left], nums[right])) - left += 1 - elif sum_ > -num: - right -= 1 - else: - left += 1 - - return list(results) -``` - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer[][]} -def three_sum(nums) - nums.sort! - results = Set.new - - nums_2 = [] - nums.each_with_index do |num, i| - next if i >= 3 && num == nums[i - 1] && num == nums[i - 2] && num == nums[i - 3] - nums_2.append(num) - end - - nums = nums_2 - - # Iterate through each number as potential first element - (0...nums.length - 2).each do |i| - break if nums[i] > 0 - - left = i + 1 - right = nums.length - 1 - - # Two-pointer approach for remaining elements - while left < right - current_sum = nums[i] + nums[left] + nums[right] - if current_sum == 0 - # Add sorted triplet to avoid duplicates - results.add([nums[i], nums[left], nums[right]]) - left += 1 - right -= 1 - elsif current_sum < 0 - left += 1 # Need larger sum - else - right -= 1 # Need smaller sum - end - end - end - - results.to_a -end -``` - -## Go - -```go -func threeSum(nums []int) [][]int { - sort.Ints(nums) - - nums2 := make([]int, 0) - for i, num := range nums { - if i >= 3 && num == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] { - continue - } - nums2 = append(nums2, num) - } - - nums = nums2 - results := make([][]int, 0) - seen := make(map[string]bool) - - for i := 0; i < len(nums)-2; i++ { - // if nums[i] > 0 { - // break - // } - - left := i + 1 - right := len(nums) - 1 - - for left < right { - sum := nums[left] + nums[right] - if sum == -nums[i] { - triplet := []int{nums[i], nums[left], nums[right]} - key := fmt.Sprintf("%d,%d,%d", triplet[0], triplet[1], triplet[2]) - if !seen[key] { - results = append(results, triplet) - seen[key] = true - } - left++ - } else if sum > -nums[i] { - right-- - } else { - left++ - } - } - } - - return results -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> threeSum(vector& nums) { - sort(nums.begin(), nums.end()); - - // Uncomment to speed up - // vector nums2; - // for (int i = 0; i < nums.size(); i++) { - // if (i >= 3 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && - // nums[i-2] == nums[i-3]) { - // continue; - // } - // nums2.push_back(nums[i]); - // } - // nums = nums2; - - vector> results; - set> seen; - - for (int i = 0; i < nums.size() - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - int left = i + 1; - int right = nums.size() - 1; - - while (left < right) { - int sum = nums[left] + nums[right]; - - if (sum == -nums[i]) { - vector triplet = {nums[i], nums[left], nums[right]}; - - if (seen.find(triplet) == seen.end()) { - results.push_back(triplet); - seen.insert(triplet); - } - - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number[][]} - */ -var threeSum = function(nums) { - nums.sort((a, b) => a - b); - - // Uncomment to speed up - // let nums2 = []; - // for (let i = 0; i < nums.length; i++) { - // if (i >= 3 && nums[i] === nums[i-1] && nums[i-1] === nums[i-2] && nums[i-2] === nums[i-3]) { - // continue; - // } - // nums2.push(nums[i]); - // } - // nums = nums2; - - const results = []; - const seen = new Set(); - - for (let i = 0; i < nums.length - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - let left = i + 1; - let right = nums.length - 1; - - while (left < right) { - const sum = nums[left] + nums[right]; - - if (sum === -nums[i]) { - const triplet = [nums[i], nums[left], nums[right]]; - const key = triplet.join(','); - if (!seen.has(key)) { - results.push(triplet); - seen.add(key); - } - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; -}; -``` - -## C# - -```csharp -public class Solution { - public IList> ThreeSum(int[] nums) { - Array.Sort(nums); - - // Uncomment to speed up - // var nums2 = new List(); - // for (int i = 0; i < nums.Length; i++) { - // if (i >= 3 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3]) { - // continue; - // } - // nums2.Add(nums[i]); - // } - // nums = nums2.ToArray(); - - var results = new List>(); - var seen = new HashSet(); - - for (int i = 0; i < nums.Length - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - int left = i + 1; - int right = nums.Length - 1; - - while (left < right) { - int sum = nums[left] + nums[right]; - if (sum == -nums[i]) { - var triplet = new List { nums[i], nums[left], nums[right] }; - string key = string.Join(",", triplet); - if (!seen.Contains(key)) { - results.Add(triplet); - seen.Add(key); - } - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; - } -} -``` - -## Java - -```java -class Solution { - public List> threeSum(int[] nums) { - Arrays.sort(nums); - - // Uncomment to speed up - // List nums2 = new ArrayList<>(); - // for (int i = 0; i < nums.length; i++) { - // if (i >= 3 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3]) { - // continue; - // } - // nums2.add(nums[i]); - // } - // nums = nums2.stream().mapToInt(i -> i).toArray(); - - List> results = new ArrayList<>(); - var seen = new HashSet<>(); - - for (int i = 0; i < nums.length - 2; i++) { - // Uncomment to speed up - // if (nums[i] > 0) { - // break; - // } - int left = i + 1; - int right = nums.length - 1; - - while (left < right) { - int sum = nums[left] + nums[right]; - if (sum == -nums[i]) { - List triplet = Arrays.asList(nums[i], nums[left], nums[right]); - if (!seen.contains(triplet)) { - results.add(triplet); - seen.add(triplet); - } - left++; - } else if (sum > -nums[i]) { - right--; - } else { - left++; - } - } - } - - return results; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -请参考`题解1`的思路,本处仅给出代码,用来解释为什么使用 `Map` 不是一个好办法。 - -## 复杂度 - -- 时间复杂度: `O(N * N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -# from collections import defaultdict - -class Solution: - def threeSum(self, nums: List[int]) -> List[List[int]]: - nums = duplicate_removed_nums(nums) - - results = set() - num_to_indices = defaultdict(list) - - for i, num in enumerate(nums): - num_to_indices[num].append(i) - - for i in range(len(nums) - 1): - for j in range(i + 1, len(nums)): - if -(nums[i] + nums[j]) in num_to_indices: - for index in num_to_indices[-(nums[i] + nums[j])]: - if index not in (i, j): - result = [nums[i], nums[j], nums[index]] - result.sort() - results.add(tuple(result)) - - return list(results) - - -def duplicate_removed_nums(nums): - num_to_count = defaultdict(int) - - for i, num in enumerate(nums): - if num_to_count[num] <= 2 or (num_to_count[num] <= 3 and num == 0): - num_to_count[num] += 1 - - new_nums = [] - - for num in num_to_count: - new_nums.extend([num] * num_to_count[num]) - - return new_nums -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[15. 三数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/15-3sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/151-reverse-words-in-a-string.md b/zh/1-1000/151-reverse-words-in-a-string.md deleted file mode 100644 index af2ac58..0000000 --- a/zh/1-1000/151-reverse-words-in-a-string.md +++ /dev/null @@ -1,188 +0,0 @@ -# 151. 反转字符串中的单词 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[151. 反转字符串中的单词 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/151-reverse-words-in-a-string),体验更佳! - -力扣链接:[151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string), 难度等级:**中等**。 - -## LeetCode “151. 反转字符串中的单词”问题描述 - -给你一个字符串 `s` ,请你反转字符串中 **单词** 的顺序。 - -**单词** 是由非空格字符组成的字符串。`s` 中使用至少一个空格将字符串中的 **单词** 分隔开。 - -返回 **单词** 顺序颠倒且 **单词** 之间用单个空格连接的结果字符串。 - -**注意**:输入字符串 `s` 中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。 - -### [示例 1] - -**输入**: `s = "the sky is blue"` - -**输出**: `"blue is sky the"` - -### [示例 2] - -**输入**: `s = " hello world "` - -**输出**: `"world hello"` - -### [示例 3] - -**输入**: `"a good example"` - -**输出**: `"example good a"` - -### [约束] - -- `1 <= s.length <= 10^4` -- `s` 包含英文大小写字母、数字和空格 `' '` -- `s` 中 **至少存在一个** 单词 - -**进阶**:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 `O(1)` 额外空间复杂度的 **原地** 解法。 - -## 思路 - -1. 拆分字符串为单词数组(需删除空字符串) -2. 反转单词顺序 -3. 用单空格连接单词 - -## 步骤 - -1. 用 split(' ') 分割字符串 -2. 删除空字符串 -3. 对得到的单词数组调用 `reverse` 反转 -4. 用 `join(' ')` 合并为最终字符串 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def reverseWords(self, s: str) -> str: - words = [word for word in s.split(' ') if word] - return ' '.join(words[::-1]) -``` - -## Java - -```java -class Solution { - public String reverseWords(String s) { - var wordList = new ArrayList(); - var words = s.split(" "); - - for (var word : words) { - if (!word.isEmpty()) { - wordList.add(word); - } - } - - int left = 0; - int right = wordList.size() - 1; - while (left < right) { - Collections.swap(wordList, left, right); - left++; - right--; - } - - return String.join(" ", wordList); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string reverseWords(string s) { - istringstream iss(s); - string word; - vector word_list; - - // 1. Extract words from the string. - // The istringstream >> operator automatically handles - // multiple spaces between words and leading/trailing spaces. - while (iss >> word) { - word_list.push_back(word); - } - - reverse(word_list.begin(), word_list.end()); - - // 2. Join the words with a single space. - string result = ""; - result = word_list[0]; - for (auto i = 1; i < word_list.size(); ++i) { - result += " "; - result += word_list[i]; - } - - return result; - } -}; - -``` - -## JavaScript - -```javascript -var reverseWords = function(s) { - const words = s.split(' ').filter((word) => word !== ''); - return words.reverse().join(' '); -}; -``` - -## Go - -```go -func reverseWords(s string) string { - words := strings.Fields(s) // Fields splits on whitespace and ignores multiple spaces - - // Reverse the words - for i, j := 0, len(words) - 1; i < j; { - words[i], words[j] = words[j], words[i] - i += 1 - j -= 1 - } - - return strings.Join(words, " ") -} -``` - -## C# - -```csharp -public class Solution { - public string ReverseWords(string s) { - // Split into words, remove empty entries, reverse - var words = s.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries).Reverse(); - return string.Join(" ", words); - } -} -``` - -## Ruby - -```ruby -def reverse_words(s) - s.split(' ').reject(&:empty?).reverse.join(' ') -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[151. 反转字符串中的单词 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/151-reverse-words-in-a-string). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/160-intersection-of-two-linked-lists.md b/zh/1-1000/160-intersection-of-two-linked-lists.md deleted file mode 100644 index 33a910c..0000000 --- a/zh/1-1000/160-intersection-of-two-linked-lists.md +++ /dev/null @@ -1,501 +0,0 @@ -# 160. 相交链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[160. 相交链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/160-intersection-of-two-linked-lists),体验更佳! - -力扣链接:[160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists), 难度等级:**简单**。 - -## LeetCode “160. 相交链表”问题描述 - -给你两个单链表的头节点 `headA` 和 `headB` ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 `null` 。 - -图示两个链表在节点 `c1` 开始相交: - -![](../../images/examples/160.png) - -题目数据 **保证** 整个链式结构中**不存在环**。 - -**注意**,函数返回结果后,链表必须 **保持其原始结构** 。 - -### [示例 1] - -![](../../images/examples/160_1.png) - -**输入**: `listA = [4,1,8,4,5], listB = [5,6,1,8,4,5]` - -**输出**: `Intersected at '8'` - -### [示例 2] - -![](../../images/examples/160_2.png) - -**输入**: `intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4]` - -**输出**: `Intersected at '2'` - -### [示例 3] - -![](../../images/examples/160_3.png) - -**输入**: `listA = [2,6,4], listB = [1,5]` - -**输出**: `No intersection` - -### [约束] - -- `listA` 中节点数目为 `m` -- `listB` 中节点数目为 `n` -- `1 <= m, n <= 3 * 10^4` -- `1 <= Node.val <= 10^5` - -
-**进阶**:你能否设计一个时间复杂度 `O(m + n)` 、仅用 `O(1)` 内存的解决方案? - -## 思路 - -这是一个典型的“相遇”问题,最好转化为现实的场景去加强理解。 - -假设你是A,B是你追求的对象,终点是学校。在上学的路上,靠后面的路程是你们都要经过的,靠前面的路程是各走各的。节点间距假定为一公里。 - -现在,某个早晨,你们同时都吃完了早饭,要骑车去学校了。而你有个目标:和B相遇,聊上几句,你会怎么做?(以示例一为例) - -
点击查看答案

你一定是先测算出她家比你家到学校远多少公里,然后**等她走完这些公里后,再出发**。这样就一定能相遇。相遇的节点就是答案。 - -1. 先把A, B两个链表的节点数计算出来。链表A的节点数为`node_count_a`,链表B的节点数为`node_count_b`。 -2. 假如`node_count_b > node_count_a`,那么对链表B做`node_count_b - node_count_a`次`node = node.next` 操作。 -3. 这时,两个链表同时重复进行`node = node.next`操作,直到找到相同的节点或者其中一个链表已经到尾部。 -

- -## 步骤 - -1. 先把A, B两个链表的节点数计算出来。链表A的节点数为`node_count_a`,链表B的节点数为`node_count_b`。 - - ```python - node_count_a = 0 - node_count_b = 0 - - node = headA - while node: - node_count_a += 1 - node = node.next - ``` - -2. 假如`node_count_b > node_count_a`,那么对链表B做`node_count_b - node_count_a`次`node = node.next` 操作。 - - ```python - bigger = headA - smaller = headB - - if node_count_b > node_count_a: - bigger = headB - smaller = headA - - for _ in range(abs(node_count_b - node_count_a)): - bigger = bigger.next - ``` - -3. 这时,两个链表同时重复进行`node = node.next`操作,直到找到相同的节点或者其中一个链表已经到尾部。 - - ```python - while bigger and smaller: - if bigger == smaller: - return bigger - - bigger = bigger.next - smaller = smaller.next - - return None - ``` - -## 复杂度 - -- 时间复杂度: `O(m + n)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -/** - * public class ListNode { - * int val; - * ListNode next; - * ListNode(int x) { - * val = x; - * next = null; - * } - * } - */ -public class Solution { - public ListNode getIntersectionNode(ListNode headA, ListNode headB) { - var nodeCountA = 0; - var nodeCountB = 0; - - var node = headA; - while (node != null) { - nodeCountA += 1; - node = node.next; - } - - node = headB; - while (node != null) { - nodeCountB += 1; - node = node.next; - } - - var bigger = headA; - var smaller = headB; - - if (nodeCountB > nodeCountA) { - bigger = headB; - smaller = headA; - } - - for (var i = 0; i < Math.abs(nodeCountB - nodeCountA); i++) { - bigger = bigger.next; - } - - while (bigger != null && smaller != null) { - if (bigger == smaller) { - return bigger; - } - - bigger = bigger.next; - smaller = smaller.next; - } - - return null; - } -} -``` - -## Python - -```python -# class ListNode: -# def __init__(self, x): -# self.val = x -# self.next = None - -class Solution: - def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: - node_count_a = 0 - node_count_b = 0 - - node = headA - while node: - node_count_a += 1 - node = node.next - - node = headB - while node: - node_count_b += 1 - node = node.next - - bigger = headA - smaller = headB - - if node_count_b > node_count_a: - bigger = headB - smaller = headA - - for _ in range(abs(node_count_b - node_count_a)): - bigger = bigger.next - - while bigger and smaller: - if bigger == smaller: - return bigger - - bigger = bigger.next - smaller = smaller.next - - return None -``` - -## JavaScript - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ -var getIntersectionNode = function (headA, headB) { - let nodeCountA = 0 - let nodeCountB = 0 - - let node = headA; - while (node != null) { - nodeCountA += 1 - node = node.next - } - - node = headB - while (node != null) { - nodeCountB += 1 - node = node.next - } - - let bigger = headA - let smaller = headB - - if (nodeCountB > nodeCountA) { - bigger = headB - smaller = headA - } - - for (var i = 0; i < Math.abs(nodeCountB - nodeCountA); i++) { - bigger = bigger.next - } - - while (bigger != null && smaller != null) { - if (bigger == smaller) { - return bigger - } - - bigger = bigger.next - smaller = smaller.next - } - - return null -}; -``` - -## C# - -```csharp -/** - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int x) { val = x; } - * } - */ -public class Solution -{ - public ListNode GetIntersectionNode(ListNode headA, ListNode headB) - { - int nodeCountA = 0; - int nodeCountB = 0; - - var node = headA; - while (node != null) - { - nodeCountA += 1; - node = node.next; - } - - node = headB; - while (node != null) - { - nodeCountB += 1; - node = node.next; - } - - var bigger = headA; - var smaller = headB; - - if (nodeCountB > nodeCountA) - { - bigger = headB; - smaller = headA; - } - - for (int i = 0; i < Math.Abs(nodeCountB - nodeCountA); i++) - { - bigger = bigger.next; - } - - while (bigger != null && smaller != null) - { - if (bigger == smaller) - { - return bigger; - } - - bigger = bigger.next; - smaller = smaller.next; - } - - return null; - } -} -``` - -## Ruby - -```ruby -# Definition for singly-linked list. -# class ListNode -# attr_accessor :val, :next -# def initialize(val) -# @val = val -# @next = nil -# end -# end - -# @param {ListNode} head_a -# @param {ListNode} head_b -# @return {ListNode} -def getIntersectionNode(head_a, head_b) - node_count_a = 0 - node_count_b = 0 - - node = head_a - while node - node_count_a += 1 - node = node.next - end - - node = head_b - while node - node_count_b += 1 - node = node.next - end - - bigger = head_a - smaller = head_b - - if node_count_b > node_count_a - bigger = head_b - smaller = head_a - end - - (node_count_b - node_count_a).abs.times do - bigger = bigger.next - end - - while bigger && smaller - return bigger if bigger == smaller - - bigger = bigger.next - smaller = smaller.next - end - - nil -end -``` - -## C++ - -```cpp -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode(int x) : val(x), next(NULL) {} - * }; - */ -class Solution { -public: - ListNode *getIntersectionNode(ListNode *head_a, ListNode *head_b) { - int node_count_a = 0; - int node_count_b = 0; - - ListNode *node = head_a; - while (node) { - node_count_a += 1; - node = node->next; - } - - node = head_b; - while (node) { - node_count_b += 1; - node = node->next; - } - - ListNode *bigger = head_a; - ListNode *smaller = head_b; - - if (node_count_b > node_count_a) { - bigger = head_b; - smaller = head_a; - } - - for (int i = 0; i < abs(node_count_b - node_count_a); i++) { - bigger = bigger->next; - } - - while (bigger && smaller) { - if (bigger == smaller) { - return bigger; - } - - bigger = bigger->next; - smaller = smaller->next; - } - - return nullptr; - } -}; -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func getIntersectionNode(headA, headB *ListNode) *ListNode { - nodeCountA := 0 - nodeCountB := 0 - - node := headA - for node != nil { - nodeCountA++ - node = node.Next - } - - node = headB - for node != nil { - nodeCountB++ - node = node.Next - } - - bigger := headA - smaller := headB - - if nodeCountB > nodeCountA { - bigger = headB - smaller = headA - } - - difference := nodeCountB - nodeCountA - if difference < 0 { - difference = -difference - } - - for i := 0; i < difference; i++ { - bigger = bigger.Next - } - - for bigger != nil && smaller != nil { - if bigger == smaller { - return bigger - } - bigger = bigger.Next - smaller = smaller.Next - } - - return nil -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[160. 相交链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/160-intersection-of-two-linked-lists). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/18-4sum.md b/zh/1-1000/18-4sum.md deleted file mode 100644 index 55919e3..0000000 --- a/zh/1-1000/18-4sum.md +++ /dev/null @@ -1,380 +0,0 @@ -# 18. 四数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[18. 四数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/18-4sum),体验更佳! - -力扣链接:[18. 四数之和](https://leetcode.cn/problems/4sum), 难度等级:**中等**。 - -## LeetCode “18. 四数之和”问题描述 - -给你一个由 `n` 个整数组成的数组 `nums` ,和一个目标值 `target` 。请你找出并返回满足下述全部条件且**不重复**的四元组 `[nums[a], nums[b], nums[c], nums[d]]` (若两个四元组元素一一对应,则认为两个四元组重复): - -- `0 <= a, b, c, d < n` -- `a`、`b`、`c` 和 `d` **互不相同** -- `nums[a] + nums[b] + nums[c] + nums[d] == target` - -你可以按 **任意顺序** 返回答案 。 - -### [示例 1] - -**输入**: `nums = [1,0,-1,0,-2,2], target = 0` - -**输出**: `[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]` - -### [示例 2] - -**输入**: `nums = [2,2,2,2,2], target = 8` - -**输出**: `[[2,2,2,2]]` - -### [约束] - -- `1 <= nums.length <= 200` -- `-10^9 <= nums[i] <= 10^9` -- `-10^9 <= target <= 10^9` - -## 思路 - -1. 本题思路同[15. 三数之和](15-3sum.md), 请点链接查看。 -2. 区别是`三数`变`四数`,处理`四数`,只需要**多加一重嵌套的循环**。 -3. 另外增加了`target`参数,计算时需要把它做为条件带入。 -4. 你可能已经看出来了,不管它是`两数`、`三数`还是`四数`,都可以用`双指针技术`。 - -## 复杂度 - -- 时间复杂度: `O(N^3)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -# If you want the program to run faster, uncomment the two places in the code. -class Solution: - def fourSum(self, nums: List[int], target: int) -> List[List[int]]: - nums.sort() - # nums_2 = [] - # for i, num in enumerate(nums): - # if i >= 4 and num == nums[i - 1] == nums[i - 2] == nums[i - 3] == nums[i - 4]: - # continue - # nums_2.append(num) - # nums = nums_2 - results = set() - - for i in range(len(nums) - 3): - for j in range(i + 1, len(nums) - 2): - num = nums[i] + nums[j] - # if num > target / 2: - # break - left = j + 1 - right = len(nums) - 1 - - while left < right: - sum_ = nums[left] + nums[right] - - if sum_ == target - num: - results.add((nums[i], nums[j], nums[left], nums[right])) - left += 1 - elif sum_ > target - num: - right -= 1 - else: - left += 1 - - return list(results) -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @param {number} target - * @return {number[][]} - */ -var fourSum = function(nums, target) { - nums.sort((a, b) => a - b); - - // Uncomment to speed up - // let nums2 = []; - // for (let i = 0; i < nums.length; i++) { - // if (i >= 4 && nums[i] === nums[i-1] && nums[i-1] === nums[i-2] && nums[i-2] === nums[i-3] && nums[i-3] === nums[i-4]) { - // continue; - // } - // nums2.push(nums[i]); - // } - // nums = nums2; - - const results = new Set(); - - for (let i = 0; i < nums.length - 3; i++) { - for (let j = i + 1; j < nums.length - 2; j++) { - const num = nums[i] + nums[j]; - // Uncomment to speed up - // if (num > target / 2) { - // break; - // } - let left = j + 1; - let right = nums.length - 1; - - while (left < right) { - const sum = nums[left] + nums[right]; - - if (sum === target - num) { - results.add([nums[i], nums[j], nums[left], nums[right]].join(',')); - left++; - } else if (sum > target - num) { - right--; - } else { - left++; - } - } - } - } - - return Array.from(results).map(str => str.split(',').map(Number)); -}; -``` - -## Ruby - -```ruby -# @param {Integer[]} nums -# @param {Integer} target -# @return {Integer[][]} -def four_sum(nums, target) - nums.sort! - - # Uncomment to speed up - # nums2 = [] - # nums.each_with_index do |num, i| - # next if i >= 4 && num == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4] - # nums2 << num - # end - # nums = nums2 - - results = Set.new - - (0..nums.length-4).each do |i| - (i+1..nums.length-3).each do |j| - num = nums[i] + nums[j] - # Uncomment to speed up - # break if num > target / 2 - left = j + 1 - right = nums.length - 1 - - while left < right - sum = nums[left] + nums[right] - - if sum == target - num - results.add([nums[i], nums[j], nums[left], nums[right]]) - left += 1 - elsif sum > target - num - right -= 1 - else - left += 1 - end - end - end - end - - results.to_a -end -``` - -## Java - -```java -class Solution { - public List> fourSum(int[] nums, int target) { - List> results = new ArrayList<>(); - - Arrays.sort(nums); - Set> seen = new HashSet<>(); - - for (int i = 0; i < nums.length - 3; i++) { - for (int j = i + 1; j < nums.length - 2; j++) { - int left = j + 1; - int right = nums.length - 1; - - while (left < right) { - long sum = (long) nums[i] + nums[j] + nums[left] + nums[right]; - - if (sum == target) { - List quadruplet = Arrays.asList(nums[i], nums[j], nums[left], nums[right]); - if (!seen.contains(quadruplet)) { - results.add(quadruplet); - seen.add(quadruplet); - } - left++; - } else if (sum < target) { - left++; - } else { - right--; - } - } - } - } - - return results; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> fourSum(vector& nums, int target) { - vector> results; - - sort(nums.begin(), nums.end()); - set> seen; - - for (int i = 0; i < nums.size() - 3; i++) { - for (int j = i + 1; j < nums.size() - 2; j++) { - int left = j + 1; - int right = nums.size() - 1; - - while (left < right) { - long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right]; - - if (sum == target) { - vector quadruplet = {nums[i], nums[j], nums[left], nums[right]}; - if (seen.find(quadruplet) == seen.end()) { - results.push_back(quadruplet); - seen.insert(quadruplet); - } - left++; - } else if (sum < target) { - left++; - } else { - right--; - } - } - } - } - - return results; - } -}; -``` - -## Go - -```go -// If you want the program to run faster, uncomment the two places in the code. - -func fourSum(nums []int, target int) [][]int { - sort.Ints(nums) - - // nums2 := make([]int, 0) - // for i := 0; i < len(nums); i++ { - // if i >= 4 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4] { - // continue - // } - // nums2 = append(nums2, nums[i]) - // } - // nums = nums2 - - results := make([][]int, 0) - seen := make(map[string]bool) - - for i := 0; i < len(nums)-3; i++ { - for j := i + 1; j < len(nums)-2; j++ { - num := nums[i] + nums[j] - // if num > target/2 { - // break - // } - left := j + 1 - right := len(nums) - 1 - - for left < right { - sum := nums[left] + nums[right] - - if sum == target-num { - quadruplet := []int{nums[i], nums[j], nums[left], nums[right]} - key := fmt.Sprintf("%d,%d,%d,%d", quadruplet[0], quadruplet[1], quadruplet[2], quadruplet[3]) - if !seen[key] { - results = append(results, quadruplet) - seen[key] = true - } - left++ - } else if sum > target-num { - right-- - } else { - left++ - } - } - } - } - - return results -} -``` - -## C# - -```csharp -// If you want the program to run faster, uncomment the two places in the code. -public class Solution { - public IList> FourSum(int[] nums, int target) { - Array.Sort(nums); - - // List nums2 = new List(); - // for (int i = 0; i < nums.Length; i++) { - // if (i >= 4 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4]) { - // continue; - // } - // nums2.Add(nums[i]); - // } - // nums = nums2.ToArray(); - - var results = new List>(); - var seen = new HashSet(); - - for (int i = 0; i < nums.Length - 3; i++) { - for (int j = i + 1; j < nums.Length - 2; j++) { - long num = (long)nums[i] + nums[j]; - // if (num > target / 2) { - // break; - // } - int left = j + 1; - int right = nums.Length - 1; - - while (left < right) { - long sum = (long)nums[left] + nums[right]; - - if (sum == target - num) { - var quadruplet = new[] { nums[i], nums[j], nums[left], nums[right] }; - string key = string.Join(",", quadruplet); - if (!seen.Contains(key)) { - results.Add(quadruplet); - seen.Add(key); - } - left++; - } else if (sum > target - num) { - right--; - } else { - left++; - } - } - } - } - - return results; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[18. 四数之和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/18-4sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/188-best-time-to-buy-and-sell-stock-iv.md b/zh/1-1000/188-best-time-to-buy-and-sell-stock-iv.md deleted file mode 100644 index 92de27c..0000000 --- a/zh/1-1000/188-best-time-to-buy-and-sell-stock-iv.md +++ /dev/null @@ -1,135 +0,0 @@ -# 188. Best Time to Buy and Sell Stock IV -LeetCode link: [188. Best Time to Buy and Sell Stock IV](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) - -## LeetCode problem description -You are given an integer array `prices` where `prices[i]` is the price of a given stock on the `i-th` day, and an integer `k`. - -Find the maximum profit you can achieve. You may complete at most `k` transactions: i.e. you may buy at most `k` times and sell at most `k` times. - -**Note**: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). -``` -------------------------------------------------------------------------------------------------------- -[Example 1] - -Input: k = 2, prices = [2,4,1] -Output: 2 - -Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2. -------------------------------------------------------------------------------------------------------- -[Example 2] - -Input: k = 2, prices = [3,2,6,5,0,3] -Output: 7 - -Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4. - Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3. -------------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= k <= 100 -1 <= prices.length <= 1000 -0 <= prices[i] <= 1000 -------------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n * k)`. -* Space: `O(n * k)`. - -## Python -```python -class Solution: - def maxProfit(self, k: int, prices: List[int]) -> int: - dp = [] - for _ in range(k): - dp.extend([-prices[0], 0]) - - for price in prices[1:]: - dc = dp.copy() - - for i in range(0, 2 * k, 2): - dp[i] = max( - dc[i], - (0 if i == 0 else dc[i - 1]) - price - ) - dp[i + 1] = max(dc[i + 1], dc[i] + price) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (k, prices) { - const dp = Array(k).fill([-prices[0], 0]).flat() - - for (const price of prices.slice(1,)) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], -price) - - for (let i = 1; i < k * 2; i++) { - dp[i] = Math.max(dc[i], dc[i - 1] + (i % 2 === 1 ? price : -price)) - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func maxProfit(k int, prices []int) int { - dp := slices.Repeat([]int{-prices[0], 0}, k) - - for _, price := range prices[1:] { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], -price) - - for i := 1; i < k * 2; i++ { - addition := price - if i % 2 == 0 { - addition *= -1 - } - dp[i] = max(dc[i], dc[i - 1] + addition) - } - } - - return dp[2 * k - 1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/19-remove-nth-node-from-end-of-list.md b/zh/1-1000/19-remove-nth-node-from-end-of-list.md deleted file mode 100644 index cd23f08..0000000 --- a/zh/1-1000/19-remove-nth-node-from-end-of-list.md +++ /dev/null @@ -1,391 +0,0 @@ -# 19. 删除链表的倒数第 N 个结点 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[19. 删除链表的倒数第 N 个结点 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/19-remove-nth-node-from-end-of-list),体验更佳! - -力扣链接:[19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list), 难度等级:**中等**。 - -## LeetCode “19. 删除链表的倒数第 N 个结点”问题描述 - -给你一个链表,删除链表的倒数第 `n` 个结点,并且返回链表的头结点。 - -### [示例 1] - -![](../../images/examples/19_1.jpg) - -**输入**: `head = [1,2,3,4,5], n = 2` - -**输出**: `[1,2,3,5]` - -### [示例 2] - -**输入**: `head = [1], n = 1` - -**输出**: `[]` - -### [示例 3] - -**输入**: `head = [1,2], n = 1` - -**输出**: `[1]` - -### [约束] - -- 链表中结点的数目为 `sz` -- `1 <= sz <= 30` -- `0 <= Node.val <= 100` -- `1 <= n <= sz` - -### [Hints] - -
- 提示 1 - Maintain two pointers and update one with a delay of n steps. - - -
- -## 思路 - -1. 删除链表的倒数第 `N` 个结点,等同于删除链表的正数第 `node_count - N` 个结点。 -2. 先求出`node_count`。 -3. 在 `index == node_count - N` 时,进行删除节点操作:`node.next = node.next.next`。 -4. 由于删除的节点可能是 `head`,所以使用虚拟节点 `dummy_node`,方便统一处理。 - -## 步骤 - -1. 求出`node_count`。 - - ```ruby - node_count = 0 - node = head - - while node - node_count += 1 - node = node.next - end - ``` - -2. 在 `index == node_count - N`时,进行删除节点操作:`node.next = node.next.next`。 - - ```ruby - index = 0 - node = head - - while node - if index == node_count - n - node.next = node.next.next - break - end - - index += 1 - node = node.next - end - ``` - -3. 由于删除的节点可能是`head`,所以使用虚拟节点`dummy_node`,方便统一处理。 - - ```ruby - dummy_head = ListNode.new # 1 - dummy_head.next = head # 2 - node = dummy_head # 3 - - # omitted code - - return dummy_head.next - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ -class Solution { - public ListNode removeNthFromEnd(ListNode head, int n) { - var nodeCount = 0; - var node = head; - - while (node != null) { - nodeCount++; - node = node.next; - } - - var index = 0; - var dummyHead = new ListNode(0, head); - node = dummyHead; - - while (node != null) { - if (index == nodeCount - n) { - node.next = node.next.next; - break; - } - - index++; - node = node.next; - } - - return dummyHead.next; - } -} -``` - -## Python - -```python -# Definition for singly-linked list. -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: - node_count = 0 - node = head - - while node: - node_count += 1 - node = node.next - - index = 0 - dummy_head = ListNode(next=head) - node = dummy_head - - while node: - if index == node_count - n: - node.next = node.next.next - break - - index += 1 - node = node.next - - return dummy_head.next -``` - -## C++ - -```cpp -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* removeNthFromEnd(ListNode* head, int n) { - auto node_count = 0; - auto node = head; - - while (node != nullptr) { - node_count += 1; - node = node->next; - } - - auto index = 0; - auto dummy_head = new ListNode(0, head); - node = dummy_head; - - for (auto i = 0; i < node_count - n; i++) { - node = node->next; - } - - auto target_node = node->next; - node->next = node->next->next; - delete target_node; - - auto result = dummy_head->next; - delete dummy_head; - return result; - } -}; -``` - -## JavaScript - -```javascript -/** - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var removeNthFromEnd = function (head, n) { - let nodeCount = 0 - let node = head - - while (node != null) { - nodeCount++ - node = node.next - } - - let index = 0 - let dummyHead = new ListNode(0, head) - node = dummyHead - - while (node != null) { - if (index == nodeCount - n) { - node.next = node.next.next - break - } - - index++ - node = node.next - } - - return dummyHead.next -}; -``` - -## C# - -```csharp -/** - * Definition for singly-linked list. - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution -{ - public ListNode RemoveNthFromEnd(ListNode head, int n) - { - int nodeCount = 0; - var node = head; - - while (node != null) - { - nodeCount++; - node = node.next; - } - - int index = 0; - var dummyHead = new ListNode(0, head); - node = dummyHead; - - while (node != null) - { - if (index == nodeCount - n) - { - node.next = node.next.next; - break; - } - - index++; - node = node.next; - } - - return dummyHead.next; - } -} -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func removeNthFromEnd(head *ListNode, n int) *ListNode { - nodeCount := 0 - node := head - - for node != nil { - nodeCount++ - node = node.Next - } - - index := 0 - dummyHead := &ListNode{0, head} - node = dummyHead - - for node != nil { - if index == nodeCount - n { - node.Next = node.Next.Next - break - } - - index++ - node = node.Next - } - - return dummyHead.Next -} -``` - -## Ruby - -```ruby -# class ListNode -# attr_accessor :val, :next -# -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def remove_nth_from_end(head, n) - node_count = 0 - node = head - - while node - node_count += 1 - node = node.next - end - - index = 0 - dummy_head = ListNode.new(0, head) - node = dummy_head - - while node - if index == node_count - n - node.next = node.next.next - break - end - - index += 1 - node = node.next - end - - dummy_head.next -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[19. 删除链表的倒数第 N 个结点 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/19-remove-nth-node-from-end-of-list). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/198-house-robber.md b/zh/1-1000/198-house-robber.md deleted file mode 100644 index a2ff275..0000000 --- a/zh/1-1000/198-house-robber.md +++ /dev/null @@ -1,204 +0,0 @@ -# 198. House Robber -LeetCode link: [198. House Robber](https://leetcode.com/problems/house-robber/) - -## LeetCode problem description -You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected, and **it will automatically contact the police if two adjacent houses were broken into on the same night**. - -Given an integer array `nums` representing the amount of money of each house, return the maximum amount of money you can rob tonight **without alerting the police**. -``` -------------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [1,2,3,1] -Output: 4 -Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). - Total amount you can rob = 1 + 3 = 4. -------------------------------------------------------------------------------------------------- -[Example 2] -Input: nums = [2,7,9,3,1] -Output: 12 -Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1). - Total amount you can rob = 2 + 9 + 1 = 12. -------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 100 -0 <= nums[i] <= 400 -------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int Rob(int[] nums) - { - if (nums.Length == 1) - return nums[0]; - - var dp = new int[nums.Length]; - dp[0] = nums[0]; - dp[1] = Math.Max(nums[0], nums[1]); - - for (var i = 2; i < dp.Length; i++) - { - dp[i] = Math.Max(dp[i - 1], dp[i - 2] + nums[i]); - } - - return dp.Last(); - } -} -``` - -## Python -### Solution 1 -```python -class Solution: - def rob(self, nums: List[int]) -> int: - if len(nums) == 1: - return nums[0] - - dp = [0] * len(nums) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i in range(2, len(dp)): - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - - return dp[-1] -``` - -## Solution 2: Using 'dp' which size is 2 -```python -class Solution: - def rob(self, nums: List[int]) -> int: - if len(nums) == 1: - return nums[0] - - dp = [nums[0], max(nums[0], nums[1])] - - for num in nums[2:]: - dc = dp.copy() - - dp[1] = max(dc[1], dc[0] + num) - dp[0] = dc[1] - - return max(dp) -``` - -## C++ -```cpp -class Solution { -public: - int rob(vector& nums) { - if (nums.size() == 1) { - return nums[0]; - } - - auto dp = vector(nums.size()); - dp[0] = nums[0]; - dp[1] = max(nums[0], nums[1]); - - for (auto i = 2; i < dp.size(); i++) { - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]); - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int rob(int[] nums) { - if (nums.length == 1) { - return nums[0]; - } - - var dp = new int[nums.length]; - dp[0] = nums[0]; - dp[1] = Math.max(nums[0], nums[1]); - - for (var i = 2; i < dp.length; i++) { - dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -```javascript -var rob = function (nums) { - if (nums.length === 1) { - return nums[0] - } - - const dp = Array(nums.length).fill(0) - dp[0] = nums[0] - dp[1] = Math.max(nums[0], nums[1]) - - for (let i = 2; i < dp.length; i++) { - dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp.at(-1) -}; -``` - -## Go -```go -func rob(nums []int) int { - if len(nums) == 1 { - return nums[0] - } - - dp := make([]int, len(nums)) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i := 2; i < len(dp); i++ { - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def rob(nums) - return nums[0] if nums.size == 1 - - dp = Array.new(nums.size, 0) - dp[0] = nums[0] - dp[1] = [ nums[0], nums[1] ].max - - (2...dp.size).each do |i| - dp[i] = [ dp[i - 1], dp[i - 2] + nums[i] ].max - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/20-valid-parentheses.md b/zh/1-1000/20-valid-parentheses.md deleted file mode 100644 index 0802eff..0000000 --- a/zh/1-1000/20-valid-parentheses.md +++ /dev/null @@ -1,357 +0,0 @@ -# 20. 有效的括号 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[20. 有效的括号 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/20-valid-parentheses),体验更佳! - -力扣链接:[20. 有效的括号](https://leetcode.cn/problems/valid-parentheses), 难度等级:**简单**。 - -## LeetCode “20. 有效的括号”问题描述 - -给定一个只包括 `(`,`)`,`{`,`}`,`[`,`]` 的字符串 `s` ,判断字符串是否有效。 - -有效字符串需满足: - -1. 左括号必须用相同类型的右括号闭合。 -2. 左括号必须以正确的顺序闭合。 -3. 每个右括号都有一个对应的相同类型的左括号。 - -### [示例 1] - -**输入**: `s = "()"` - -**输出**: `true` - -### [示例 2] - -**输入**: `s = "()[]{}"` - -**输出**: `true` - -### [示例 3] - -**输入**: `s = "(]"` - -**输出**: `false` - -### [示例 4] - -**输入**: `s = "([])"` - -**输出**: `true` - -### [约束] - -- `1 <= s.length <= 10000` -- `s` 仅由括号 `()[]{}` 组成 - -### [Hints] - -
- 提示 1 - Use a stack of characters. - - -
- -
- 提示 2 - When you encounter an opening bracket, push it to the top of the stack. - - -
- -
- 提示 3 - When you encounter a closing bracket, check if the top of the stack was the opening for it. If yes, pop it from the stack. Otherwise, return false. - - -
- -## 思路 - -1. 括号匹配关注的主要是`前一个字符`与`当前字符`。有两种情况要考虑: - 1. 如果`当前字符`是左括号,则不需要匹配,直接保存起来。 - 2. 如果`当前字符`是右括号,并且`前一个字符`与`当前字符`配成了一对,则这两个字符都可以**消失**了;反之,如果配对失败,直接返回`false`。 -2. 这种关注`前一个字符`与`当前字符`的场景,适合用`栈`实现。 -3. 左右括号之间的对应关系可以保存在一个`Map`中。 -4. 最后,如果栈为空,说明全部配对成功,返回`true`;否则返回`false`。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## JavaScript - -```javascript -/** - * @param {string} s - * @return {boolean} - */ -var isValid = function (s) { - const closeToOpen = new Map([ - [')', '('], - ['}', '{'], - [']', '['], - ]) - const stack = [] - - for (const char of s) { - if (!closeToOpen.has(char)) { - // is open bracket - stack.push(char) - continue - } - // is close bracket - - if (stack.length === 0) { - return false - } - - // stack top value doesn't match the expected value - if (stack.pop() != closeToOpen.get(char)) { - return false - } - } - - return stack.length === 0 -}; -``` - -## Python - -```python -class Solution: - def isValid(self, s: str) -> bool: - # Map closing brackets to their opening brackets - close_to_open = { - ')': '(', - '}': '{', - ']': '[', - } - stack = [] - - for char in s: - if char not in close_to_open: - # is open bracket - stack.append(char) - continue - # is close bracket - - if not stack: - return False - - # stack top value doesn't match the expected value - if stack.pop() != close_to_open[char]: - return False - - return not stack -``` - -## Java - -```java -class Solution { - public boolean isValid(String s) { - // Map closing brackets to their opening brackets - var closeToOpen = new HashMap(); - closeToOpen.put(')', '('); - closeToOpen.put('}', '{'); - closeToOpen.put(']', '['); - - var stack = new Stack(); - - for (char c : s.toCharArray()) { - if (!closeToOpen.containsKey(c)) { - // is open bracket - stack.push(c); - continue; - } - // is close bracket - - if (stack.isEmpty()) { - return false; - } - - // stack top value doesn't match the expected value - if (stack.pop() != closeToOpen.get(c)) { - return false; - } - } - - return stack.isEmpty(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool isValid(string s) { - // Map closing brackets to their opening brackets - unordered_map closeToOpen = { - {')', '('}, - {'}', '{'}, - {']', '['} - }; - - stack st; - - for (char c : s) { - if (closeToOpen.find(c) == closeToOpen.end()) { - // is open bracket - st.push(c); - continue; - } - // is close bracket - - if (st.empty()) { - return false; - } - - // stack top value doesn't match the expected value - if (st.top() != closeToOpen[c]) { - return false; - } - - st.pop(); - } - - return st.empty(); - } -}; -``` - -## C# - -```csharp -public class Solution -{ - public bool IsValid(string s) - { - // Map closing brackets to their opening brackets - var closeToOpen = new Dictionary() - { - {')', '('}, - {'}', '{'}, - {']', '['} - }; - - var stack = new Stack(); - - foreach (char c in s) { - if (!closeToOpen.ContainsKey(c)) - { - // is open bracket - stack.Push(c); - continue; - } - // is close bracket - - if (stack.Count == 0) - { - return false; - } - - // stack top value doesn't match the expected value - if (stack.Pop() != closeToOpen[c]) - { - return false; - } - } - - return stack.Count == 0; - } -} -``` - -## Go - -```go -func isValid(s string) bool { - // Map closing brackets to their opening brackets - closeToOpen := map[rune]rune{ - ')': '(', - '}': '{', - ']': '[', - } - - stack := []rune{} - - for _, char := range s { - if _, isClose := closeToOpen[char]; !isClose { - // is open bracket - stack = append(stack, char) - continue - } - // is close bracket - - if len(stack) == 0 { - return false - } - - lastChar := stack[len(stack) - 1] - - // stack top value doesn't match the expected value - if lastChar != closeToOpen[char] { - return false - } - - stack = stack[:len(stack) - 1] // pop operation - } - - return len(stack) == 0 -} -``` - -## Ruby - -```ruby -# @param {String} s -# @return {Boolean} -def is_valid(s) - # Map closing brackets to their opening brackets - close_to_open = { - ')' => '(', - '}' => '{', - ']' => '[' - } - - stack = [] - - s.each_char do |char| - if !close_to_open.key?(char) - # is open bracket - stack.push(char) - next - end - # is close bracket - - if stack.empty? - return false - end - - # stack top value doesn't match the expected value - if stack.pop != close_to_open[char] - return false - end - end - - stack.empty? -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[20. 有效的括号 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/20-valid-parentheses). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/200-number-of-islands-2.md b/zh/1-1000/200-number-of-islands-2.md deleted file mode 100644 index 7b54515..0000000 --- a/zh/1-1000/200-number-of-islands-2.md +++ /dev/null @@ -1,476 +0,0 @@ -# 200. Number of Islands (Solution 2: 'Depth-First Search' by Iteration) -LeetCode link: [200. Number of Islands](https://leetcode.com/problems/number-of-islands/) - -## LeetCode problem description -Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return the number of islands. - -An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - -### Example 1 -``` -Input: grid = [ - ["1","1","1","1","0"], - ["1","1","0","1","0"], - ["1","1","0","0","0"], - ["0","0","0","0","0"] -] -Output: 1 -``` - -### Example 2 -``` -Input: grid = [ - ["1","1","0","0","0"], - ["1","1","0","0","0"], - ["0","0","1","0","0"], - ["0","0","0","1","1"] -] -Output: 3 -``` - -### Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 300` -- `grid[i][j]` is `'0'` or `'1'`. - -# Thoughts -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Finding the number of islands is to find the number of `connected components`. - -Walk from one vertex (land) to the adjacent vertices until all vertices on the island are visited. - -## Steps -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * Mark each found land as `V` which represents `visited`. Visited lands don't need to be visited again. -1. After all lands on an island have been visited, look for the next non-visited land. -1. Repeat the above two steps until all the lands have been `visited`. - -### Solution 1: 'Depth-First Search' by Recursion -Please click [Depth-First Search by Recursion Solution](200-number-of-islands.md) for `200. Number of Islands` to view. - -## Solution 2: 'Depth-First Search' by Iteration -![](../../images/binary_tree_DFS_1.png) - -In solution 1, we have known how to traverse a graph by recursion. Computer language support for recursive calls is implemented through stacks. -For every recursive solution, there is an iterative solution, which means the same problem can be solved using loops. -The benefit of using iteration is better program performance. After all, recursive calls are expensive. - -Maintaining a stack by yourself can accomplish the same function as recursive calls. - -From this sample code bellow, you can see that starting from a vertex, through recursive calls, it goes up until it can't go any further, turns right, and continues up. The priority order of directions is `up, right, down, left`. -```java -vertexStack.push({i, j - 1}); // left -vertexStack.push({i + 1, j}); // down -vertexStack.push({i, j + 1}); // right -vertexStack.push({i - 1, j}); // up -``` - -## Solution 3: Breadth-First Search -Please click [Breadth-First Search Solution](200-number-of-islands-3.md) for `200. Number of Islands` to view. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -# Python -```python -class Solution: - def __init__(self): - self.grid = None - self.vertex_stack = [] - - def numIslands(self, grid: List[List[str]]) -> int: - island_count = 0 - self.grid = grid - - for i, row in enumerate(grid): - for j, value in enumerate(row): - if value == '1': - island_count += 1 - - self.depth_first_search((i, j)) - - return island_count - - def depth_first_search(self, vertex): - self.vertex_stack.append(vertex) - - while self.vertex_stack: - i, j = self.vertex_stack.pop() - - if i < 0 or i >= len(self.grid): - continue - - if j < 0 or j >= len(self.grid[0]): - continue - - if self.grid[i][j] != '1': - continue - - self.grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - self.vertex_stack.append((i, j - 1)) - self.vertex_stack.append((i + 1, j)) - self.vertex_stack.append((i, j + 1)) - self.vertex_stack.append((i - 1, j)) -``` - -# Java -```java -class Solution { - Stack vertexStack = new Stack<>(); - char[][] grid; - - public int numIslands(char[][] grid) { - this.grid = grid; - var islandCount = 0; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == '1') { - islandCount++; - - depthFirstSearch(new int[]{i, j}); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int[] vertex) { - vertexStack.push(vertex); - - while (!vertexStack.empty()) { - vertex = vertexStack.pop(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.length) { - continue; - } - - if (j < 0 || j >= grid[0].length) { - continue; - } - - if (grid[i][j] != '1') { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.push(new int[]{i, j - 1}); - vertexStack.push(new int[]{i + 1, j}); - vertexStack.push(new int[]{i, j + 1}); - vertexStack.push(new int[]{i - 1, j}); - } - } -} -``` - -# C++ -```cpp -class Solution { -public: - int numIslands(vector>& grid) { - grid_ = grid; - auto island_count = 0; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == '1') { - island_count++; - - depth_first_search(i, j); - } - } - } - - return island_count; - } - -private: - vector> grid_; - stack> vertex_stack; - - void depth_first_search(int i1, int j1) { - vertex_stack.push({i1, j1}); - - while (!vertex_stack.empty()) { - pair vertex = vertex_stack.top(); - vertex_stack.pop(); - - int i = vertex.first; - int j = vertex.second; - - if (i < 0 || i >= grid_.size()) { - continue; - } - - if (j < 0 || j >= grid_[0].size()) { - continue; - } - - if (grid_[i][j] != '1') { - continue; - } - - grid_[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertex_stack.push({i, j - 1}); - vertex_stack.push({i + 1, j}); - vertex_stack.push({i, j + 1}); - vertex_stack.push({i - 1, j}); - } - } -}; -``` - -# JavaScript -```JavaScript -let grid -let vertexStack - -var numIslands = function (grid_) { - grid = grid_ - vertexStack = [] - let islandCount = 0 - - grid.forEach((row, i) => { - row.forEach((item, j) => { - if (item === '1') { - islandCount++ - - depthFirstSearch([i, j]) - } - }) - }) - - return islandCount -}; - -function depthFirstSearch(vertex) { - vertexStack.push(vertex) - - while (vertexStack.length > 0) { - const [i, j] = vertexStack.pop() - - if (i < 0 || i >= grid.length) { - continue - } - - if (j < 0 || j >= grid[0].length) { - continue - } - - if (grid[i][j] != '1') { - continue - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.push([i, j - 1]) - vertexStack.push([i + 1, j]) - vertexStack.push([i, j + 1]) - vertexStack.push([i - 1, j]) - } -} -``` - -# C# -```c# -public class Solution -{ - Stack vertexStack = new Stack(); - char[][] grid; - - public int NumIslands(char[][] grid) - { - this.grid = grid; - int islandCount = 0; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == '1') - { - islandCount++; - - depthFirstSearch([i, j]); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int[] vertex) - { - vertexStack.Push(vertex); - - while (vertexStack.Count > 0) - { - vertex = vertexStack.Pop(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.Length) - { - continue; - } - if (j < 0 || j >= grid[0].Length) - { - continue; - } - if (grid[i][j] != '1') - { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.Push([i, j - 1]); - vertexStack.Push([i + 1, j]); - vertexStack.Push([i, j + 1]); - vertexStack.Push([i - 1, j]); - } - } -} -``` - -# Go -```go -var grid [][]byte -var vertexStack = arraystack.New() - -func numIslands(grid_ [][]byte) int { - grid = grid_ - vertexStack.Clear() - islandCount := 0 - - for i, row := range grid { - for j, value := range row { - if value == '1' { - islandCount++ - - depthFirstSearch([]int{i, j}) - } - } - } - - return islandCount -} - -func depthFirstSearch(vertex []int) { - vertexStack.Push(vertex) - - for !vertexStack.Empty() { - vertex, _ := vertexStack.Pop(); - - i := vertex.([]int)[0] - j := vertex.([]int)[1] - - if i < 0 || i >= len(grid) { - continue - } - - if j < 0 || j >= len(grid[0]) { - continue - } - - if grid[i][j] != '1' { - continue - } - - grid[i][j] = 'V' // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexStack.Push([]int{i, j - 1}) - vertexStack.Push([]int{i + 1, j}) - vertexStack.Push([]int{i, j + 1}) - vertexStack.Push([]int{i - 1, j}) - } -} -``` - -# Ruby -```ruby -def num_islands(grid) - @grid = grid - @vertex_stack = [] - island_count = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == '1' - depth_first_search([i, j]) - - island_count += 1 - end - end - end - - island_count -end - -def depth_first_search(vertex) - @vertex_stack << vertex - - while !@vertex_stack.empty? - vertex = @vertex_stack.pop - - i = vertex[0] - j = vertex[1] - - next if i < 0 || i >= @grid.size - - next if j < 0 || j >= @grid[0].size - - next if @grid[i][j] != '1' - - @grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as pushing `vertex_stack`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - @vertex_stack << [i, j - 1] - @vertex_stack << [i + 1, j] - @vertex_stack << [i, j + 1] - @vertex_stack << [i - 1, j] - end -end -``` - -# C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/200-number-of-islands-3.md b/zh/1-1000/200-number-of-islands-3.md deleted file mode 100644 index 5fe039b..0000000 --- a/zh/1-1000/200-number-of-islands-3.md +++ /dev/null @@ -1,468 +0,0 @@ -# 200. Number of Islands (Solution 3: Breadth-First Search) -LeetCode link: [200. Number of Islands](https://leetcode.com/problems/number-of-islands/) - -## LeetCode problem description -Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return the number of islands. - -An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - -### Example 1 -``` -Input: grid = [ - ["1","1","1","1","0"], - ["1","1","0","1","0"], - ["1","1","0","0","0"], - ["0","0","0","0","0"] -] -Output: 1 -``` - -### Example 2 -``` -Input: grid = [ - ["1","1","0","0","0"], - ["1","1","0","0","0"], - ["0","0","1","0","0"], - ["0","0","0","1","1"] -] -Output: 3 -``` - -### Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 300` -- `grid[i][j]` is `'0'` or `'1'`. - -# Thoughts -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Finding the number of islands is to find the number of `connected components`. - -Walk from one vertex (land) to the adjacent vertices until all vertices on the island are visited. - -## Steps -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * Mark each found land as `V` which represents `visited`. Visited lands don't need to be visited again. -1. After all lands on an island have been visited, look for the next non-visited land. -1. Repeat the above two steps until all the lands have been `visited`. - -### Solution 1: 'Depth-First Search' by Recursion -Please click [Depth-First Search by Recursion Solution](200-number-of-islands.md) for `200. Number of Islands` to view. - -## Solution 2: 'Depth-First Search' by Iteration -Please click [Depth-First Search by Iteration Solution](200-number-of-islands-2.md) for `200. Number of Islands` to view. - -## Solution 3: Breadth-First Search -![](../../images/binary_tree_BFS_1.gif) - -As shown in the figure above, **breadth-first search** can be thought of as visiting vertices in rounds and rounds. - -It emphasizes first-in-first-out, so a **queue** is needed. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Python -```python -class Solution: - def __init__(self): - self.grid = None - self.vertex_queue = deque() - - def numIslands(self, grid: List[List[str]]) -> int: - island_count = 0 - self.grid = grid - - for i, row in enumerate(grid): - for j, value in enumerate(row): - if value == '1': - island_count += 1 - - self.breadth_first_search((i, j)) - - return island_count - - def breadth_first_search(self, vertex): - self.vertex_queue.append(vertex) - - while self.vertex_queue: - i, j = self.vertex_queue.popleft() - - if i < 0 or i >= len(self.grid): - continue - - if j < 0 or j >= len(self.grid[0]): - continue - - if self.grid[i][j] != '1': - continue - - self.grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - self.vertex_queue.append((i - 1, j)) - self.vertex_queue.append((i, j + 1)) - self.vertex_queue.append((i + 1, j)) - self.vertex_queue.append((i, j - 1)) -``` - -## Java -```java -class Solution { - Queue vertexQueue = new ArrayDeque<>(); - char[][] grid; - - public int numIslands(char[][] grid) { - this.grid = grid; - var islandCount = 0; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == '1') { - islandCount++; - - breadthFirstSearch(new int[]{i, j}); - } - } - } - - return islandCount; - } - - void breadthFirstSearch(int[] vertex) { - vertexQueue.add(vertex); - - while (!vertexQueue.isEmpty()) { - vertex = vertexQueue.poll(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.length) { - continue; - } - - if (j < 0 || j >= grid[0].length) { - continue; - } - - if (grid[i][j] != '1') { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.add(new int[]{i - 1, j}); - vertexQueue.add(new int[]{i, j + 1}); - vertexQueue.add(new int[]{i + 1, j}); - vertexQueue.add(new int[]{i, j - 1}); - } - } -} -``` - -## C++ -```cpp -class Solution { -private: - vector> grid_; - queue> vertex_queue; - - void breadth_first_search(int i1, int j1) { - vertex_queue.push({i1, j1}); - - while (!vertex_queue.empty()) { - pair vertex = vertex_queue.front(); - vertex_queue.pop(); - - int i = vertex.first; - int j = vertex.second; - - if (i < 0 || i >= grid_.size()) { - continue; - } - - if (j < 0 || j >= grid_[0].size()) { - continue; - } - - if (grid_[i][j] != '1') { - continue; - } - - grid_[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertex_queue.push({i - 1, j}); - vertex_queue.push({i, j + 1}); - vertex_queue.push({i + 1, j}); - vertex_queue.push({i, j - 1}); - } - } - -public: - int numIslands(vector>& grid) { - grid_ = grid; - auto island_count = 0; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == '1') { - island_count++; - - breadth_first_search(i, j); - } - } - } - - return island_count; - } -}; -``` - -## JavaScript -```JavaScript -let grid -let vertexQueue - -var numIslands = function (grid_) { - grid = grid_ - vertexQueue = new Queue() // github.com/datastructures-js/queue - let islandCount = 0 - - grid.forEach((row, i) => { - row.forEach((item, j) => { - if (item === '1') { - islandCount++ - - breadthFirstSearch([i, j]) - } - }) - }) - - return islandCount -}; - -function breadthFirstSearch(vertex) { - vertexQueue.enqueue(vertex) - - while (!vertexQueue.isEmpty()) { - const [i, j] = vertexQueue.dequeue() - - if (i < 0 || i >= grid.length) { - continue - } - - if (j < 0 || j >= grid[0].length) { - continue - } - - if (grid[i][j] != '1') { - continue - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.enqueue([i - 1, j]) - vertexQueue.enqueue([i, j + 1]) - vertexQueue.enqueue([i + 1, j]) - vertexQueue.enqueue([i, j - 1]) - } -} -``` - -## C# -```c# -public class Solution -{ - Queue vertexQueue = new Queue(); - char[][] grid; - - public int NumIslands(char[][] grid) - { - this.grid = grid; - int islandCount = 0; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == '1') - { - islandCount++; - - breadthFirstSearch([i, j]); - } - } - } - - return islandCount; - } - - void breadthFirstSearch(int[] vertex) - { - vertexQueue.Enqueue(vertex); - - while (vertexQueue.Count > 0) - { - vertex = vertexQueue.Dequeue(); - int i = vertex[0]; - int j = vertex[1]; - - if (i < 0 || i >= grid.Length) - { - continue; - } - - if (j < 0 || j >= grid[0].Length) - { - continue; - } - - if (grid[i][j] != '1') - { - continue; - } - - grid[i][j] = 'V'; // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.Enqueue([i - 1, j]); - vertexQueue.Enqueue([i, j + 1]); - vertexQueue.Enqueue([i + 1, j]); - vertexQueue.Enqueue([i, j - 1]); - } - } -} -``` - -## Go -```go -var grid [][]byte -var vertexQueue = linkedlistqueue.New() - -func numIslands(grid_ [][]byte) int { - grid = grid_ - vertexQueue.Clear() - islandCount := 0 - - for i, row := range grid { - for j, value := range row { - if value == '1' { - islandCount++ - - breadthFirstSearch([]int{i, j}) - } - } - } - - return islandCount -} - -func breadthFirstSearch(vertex []int) { - vertexQueue.Enqueue(vertex) - - for !vertexQueue.Empty() { - vertex, _ := vertexQueue.Dequeue(); - - i := vertex.([]int)[0] - j := vertex.([]int)[1] - - if i < 0 || i >= len(grid) { - continue - } - - if j < 0 || j >= len(grid[0]) { - continue - } - - if grid[i][j] != '1' { - continue - } - - grid[i][j] = 'V' // For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - vertexQueue.Enqueue([]int{i - 1, j}) - vertexQueue.Enqueue([]int{i, j + 1}) - vertexQueue.Enqueue([]int{i + 1, j}) - vertexQueue.Enqueue([]int{i, j - 1}) - } -} -``` - -## Ruby -```ruby -def num_islands(grid) - @grid = grid - @vertex_queue = Containers::Queue.new - island_count = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == '1' - breadth_first_search([i, j]) - - island_count += 1 - end - end - end - - island_count -end - -def breadth_first_search(vertex) - @vertex_queue.push(vertex) - - while !@vertex_queue.empty? - vertex = @vertex_queue.pop - - i = vertex[0] - j = vertex[1] - - next if i < 0 || i >= @grid.size - - next if j < 0 || j >= @grid[0].size - - next if @grid[i][j] != '1' - - @grid[i][j] = 'V' # For island problems, its OK to mark visited at this place. For other graph problems, we need to use `visited_vertex_set` and mark visited as soon as enqueuing `vertex_queue`. Because the adjacent veticies could be a lot, and it will cause performance issue. - - @vertex_queue << [i - 1, j] - @vertex_queue << [i, j + 1] - @vertex_queue << [i + 1, j] - @vertex_queue << [i, j - 1] - end -end -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/200-number-of-islands.md b/zh/1-1000/200-number-of-islands.md deleted file mode 100644 index 7149d4c..0000000 --- a/zh/1-1000/200-number-of-islands.md +++ /dev/null @@ -1,395 +0,0 @@ -# 200. Number of Islands (Solution 1: 'Depth-First Search' by Recursion) -LeetCode link: [200. Number of Islands](https://leetcode.com/problems/number-of-islands/) - -# LeetCode problem description -Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return the number of islands. - -An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. - -## Example 1 -``` -Input: grid = [ - ["1","1","1","1","0"], - ["1","1","0","1","0"], - ["1","1","0","0","0"], - ["0","0","0","0","0"] -] -Output: 1 -``` - -## Example 2 -``` -Input: grid = [ - ["1","1","0","0","0"], - ["1","1","0","0","0"], - ["0","0","1","0","0"], - ["0","0","0","1","1"] -] -Output: 3 -``` - -## Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 300` -- `grid[i][j]` is `'0'` or `'1'`. - -# Intuition -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Finding the number of islands is to find the number of `connected components`. - -Walk from one vertex (land) to the adjacent vertices until all vertices on the island are visited. - -## Approach -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * Mark each found land as `V` which represents `visited`. Visited lands don't need to be visited again. -1. After all lands on an island have been visited, look for the next non-visited land. -1. Repeat the above two steps until all the lands have been `visited`. - -## Solution 1: 'Depth-First Search' by Recursion -![](../../images/binary_tree_DFS_1.png) - -From this sample code bellow, you can see that starting from a vertex, through recursive calls, it goes up until it can't go any further, turns right, and continues up. The priority order of directions is `up, right, down, left`. -```java -depth_first_search(i - 1, j); // up -depth_first_search(i, j + 1); // right -depth_first_search(i + 1, j); // down -depth_first_search(i, j - 1); // left -``` - -## Solution 2: 'Depth-First Search' by Iteration -Please click [Depth-First Search by Iteration Solution](200-number-of-islands-2.md) for `200. Number of Islands` to view. - -## Solution 3: Breadth-First Search -Please click [Breadth-First Search Solution](200-number-of-islands-3.md) for `200. Number of Islands` to view. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -# Python -```python -class Solution: - def __init__(self): - self.grid = None - - def numIslands(self, grid: List[List[str]]) -> int: - self.grid = grid - island_count = 0 - - for i, row in enumerate(grid): - for j, value in enumerate(row): - if value == '1': - island_count += 1 - - self.depth_first_search(i, j) - - return island_count - - def depth_first_search(self, i, j): - if i < 0 or i >= len(self.grid): - return - - if j < 0 or j >= len(self.grid[0]): - return - - if self.grid[i][j] != '1': - return - - self.grid[i][j] = 'V' - - self.depth_first_search(i - 1, j) - self.depth_first_search(i, j + 1) - self.depth_first_search(i + 1, j) - self.depth_first_search(i, j - 1) -``` - -# Java -```java -class Solution { - char[][] grid; - - public int numIslands(char[][] grid) { - this.grid = grid; - var islandCount = 0; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == '1') { - islandCount++; - - depthFirstSearch(i, j); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int i, int j) { - if (i < 0 || i >= grid.length) { - return; - } - - if (j < 0 || j >= grid[0].length) { - return; - } - - if (grid[i][j] != '1') { - return; - } - - grid[i][j] = 'V'; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# C++ -```cpp -class Solution { -public: - int numIslands(vector>& grid) { - grid_ = grid; - auto island_count = 0; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == '1') { - island_count++; - - depth_first_search(i, j); - } - } - } - - return island_count; - } - -private: - vector> grid_; - - void depth_first_search(int i, int j) { - if (i < 0 || i >= grid_.size() || - j < 0 || j >= grid_[0].size() || - grid_[i][j] != '1') { - return; - } - - grid_[i][j] = 'V'; - - depth_first_search(i - 1, j); - depth_first_search(i, j + 1); - depth_first_search(i + 1, j); - depth_first_search(i, j - 1); - } -}; -``` - -# JavaScript -```JavaScript -let grid - -var numIslands = function (grid_) { - grid = grid_ - let islandCount = 0 - - grid.forEach((row, i) => { - row.forEach((value, j) => { - if (value === '1') { - islandCount++ - - depthFirstSearch(i, j) - } - }) - }) - - return islandCount -}; - -function depthFirstSearch(i, j) { - if (i < 0 || i >= grid.length) { - return - } - - if (j < 0 || j >= grid[0].length) { - return - } - - if (grid[i][j] != '1') { - return - } - - grid[i][j] = 'V'; - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# C# -```c# -public class Solution -{ - char[][] grid; - - public int NumIslands(char[][] grid) - { - this.grid = grid; - int islandCount = 0; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == '1') - { - islandCount++; - - depthFirstSearch(i, j); - } - } - } - - return islandCount; - } - - void depthFirstSearch(int i, int j) - { - if (i < 0 || i >= grid.Length) - return; - - if (j < 0 || j >= grid[0].Length) - return; - - if (grid[i][j] != '1') - return; - - grid[i][j] = 'V'; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# Go -```go -var grid [][]byte - -func numIslands(grid_ [][]byte) int { - grid = grid_ - islandCount := 0 - - for i, row := range grid { - for j, value := range row { - if value == '1' { - islandCount++ - - depthFirstSearch(i, j) - } - } - } - - return islandCount -} - -func depthFirstSearch(i int, j int) { - if i < 0 || i >= len(grid) { - return - } - - if j < 0 || j >= len(grid[0]) { - return - } - - if grid[i][j] != '1' { - return - } - - grid[i][j] = 'V' - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# Ruby -```Ruby -def num_islands(grid) - @grid = grid - island_count = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == '1' - depth_first_search(i, j) - - island_count += 1 - end - end - end - - island_count -end - -def depth_first_search(i, j) - return if i < 0 || i >= @grid.size - - return if j < 0 || j >= @grid[0].size - - return if @grid[i][j] != '1' - - @grid[i][j] = 'V' - - depth_first_search(i - 1, j) - depth_first_search(i, j + 1) - depth_first_search(i + 1, j) - depth_first_search(i, j - 1) -end -``` - -# C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/202-happy-number.md b/zh/1-1000/202-happy-number.md deleted file mode 100644 index 4052dd4..0000000 --- a/zh/1-1000/202-happy-number.md +++ /dev/null @@ -1,280 +0,0 @@ -# 202. 快乐数 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[202. 快乐数 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/202-happy-number),体验更佳! - -力扣链接:[202. 快乐数](https://leetcode.cn/problems/happy-number), 难度等级:**简单**。 - -## LeetCode “202. 快乐数”问题描述 - -编写一个算法来判断一个数 `n` 是不是快乐数。 - -「**快乐数**」 定义为: - -- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 -- 然后重复这个过程直到这个数变为 `1`,也可能是 **无限循环** 但始终变不到 `1`。 -- 如果这个过程 **结果为** `1`,那么这个数就是快乐数。 -- 如果 `n` 是 *快乐数* 就返回 `true` ;不是,则返回 `false` 。 - -### [示例 1] - -**输入**: `n = 19` - -**输出**: `true` - -**解释**: - -

12 + 92 = 82
-82 + 22 = 68
-62 + 82 = 100
-12 + 02 + 02 = 1

- - -### [示例 2] - -**输入**: `n = 2` - -**输出**: `false` - -### [约束] - -- `1 <= n <= 2^31 - 1` - -## 思路 - -1. 递归调用`isHappy(n)`比较方便,每次只需要生成新的`n`作为参数。 -2. 如果`n`已经出现过了,说明进入了循环,`return false`。可以用`Set`保存已经出现过的`n`。 -3. Go是迭代解法,其他语言都是递归解法。 - -## 步骤 - -1. 生成新的`n`作为`isHappy()`的参数。 - - ```javascript - let sum = 0 - - for (const digit of n.toString()) { - sum += Math.pow(Number(digit), 2) - } - - // omitted code - - return isHappy(sum) - ``` - -2. 如果`n`已经出现过了,说明进入了循环,`return false`。可以用`Set`保存已经出现过的`n`。 - - ```javascript - var isHappy = function (n, appearedNums) { - appearedNums ||= new Set() // 1 - let sum = 0 - - for (const digit of n.toString()) { - sum += Math.pow(Number(digit), 2) - } - - if (sum == 1) { - return true - } - - if (appearedNums.has(sum)) { // 2 - return false - } - - appearedNums.add(sum) // 3 - - return isHappy(sum, appearedNums) - }; - ``` - -## 复杂度 - -- 时间复杂度: `O(log N)`. -- 空间复杂度: `O(log N)`. - -## Java - -```java -class Solution { - private HashSet appearedNums = new HashSet<>(); - - public boolean isHappy(int n) { - appearedNums.add(n); - - var sum = 0; - - for (var digit : String.valueOf(n).toCharArray()) { - sum += Math.pow(digit - '0', 2); - } - - if (sum == 1) { - return true; - } - - if (appearedNums.contains(sum)) { - return false; - } - - return isHappy(sum); - } -} -``` - -## Python - -```python -class Solution: - def __init__(self): - self.appeared_nums = set() - - def isHappy(self, n: int) -> bool: - self.appeared_nums.add(n) - - number = sum([int(digit) ** 2 for digit in str(n)]) - - if number == 1: - return True - - if number in self.appeared_nums: - return False - - return self.isHappy(number) -``` - -## JavaScript - -```javascript -var isHappy = function (n, appearedNums) { - appearedNums ||= new Set() - let sum = 0 - - for (const digit of n.toString()) { - sum += Math.pow(Number(digit), 2) - } - - if (sum == 1) { - return true - } - - if (appearedNums.has(sum)) { - return false - } - - appearedNums.add(sum) - - return isHappy(sum, appearedNums) -}; -``` - -## C# - -```csharp -public class Solution -{ - HashSet appearedNums = new HashSet(); - - public bool IsHappy(int n) - { - appearedNums.Add(n); - - int sum = 0; - - foreach (char digit in n.ToString().ToCharArray()) - sum += (int)Math.Pow(digit - '0', 2); - - if (sum == 1) - return true; - - if (appearedNums.Contains(sum)) - return false; - - return IsHappy(sum); - } -} -``` - -## Go - -```go -func isHappy(n int) bool { - // Use map to track seen numbers - seen := make(map[int]bool) - - for n != 1 && !seen[n] { - seen[n] = true - n = sumOfSquaredDigits(n) - } - - return n == 1 -} - -func sumOfSquaredDigits(n int) int { - sum := 0 - nStr := strconv.Itoa(n) - for i := 0; i < len(nStr); i++ { - digit := int(nStr[i] - '0') - sum += digit * digit - } - return sum -} -``` - -## C++ - -```cpp -class Solution { -public: - bool isHappy(int n) { - if (n == 1) { - return true; - } - - if (appeared_nums_.count(n)) { - return false; - } - - appeared_nums_.insert(n); - - return isHappy(getSum(n)); - } - -private: - unordered_set appeared_nums_; - - int getSum(int n) { - string n_str = to_string(n); - int sum = 0; - for (char digit : n_str) { - sum += (digit - '0') * (digit - '0'); - } - return sum; - } -}; -``` - -## Ruby - -```ruby -def is_happy(n, appeared_nums = Set.new) - return true if n == 1 - return false if appeared_nums.include?(n) - - appeared_nums.add(n) - sum = n.to_s.chars.map { |digit| digit.to_i ** 2 }.sum - - is_happy(sum, appeared_nums) -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[202. 快乐数 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/202-happy-number). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/203-remove-linked-list-elements.md b/zh/1-1000/203-remove-linked-list-elements.md deleted file mode 100644 index 1efd924..0000000 --- a/zh/1-1000/203-remove-linked-list-elements.md +++ /dev/null @@ -1,273 +0,0 @@ -# 203. 移除链表元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[203. 移除链表元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/203-remove-linked-list-elements),体验更佳! - -力扣链接:[203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements), 难度等级:**简单**。 - -## LeetCode “203. 移除链表元素”问题描述 - -给你一个链表的头节点 `head` 和一个整数 `val` ,请你删除链表中所有满足 `Node.val == val` 的节点,并返回 **新的头节点** 。 - -### [示例 1] - -![](../../images/examples/203_1.jpg) - -**输入**: `head = [1,2,6,3,4,5,6], val = 6` - -**输出**: `[1,2,3,4,5]` - -### [示例 2] - -**输入**: `head = [], val = 1` - -**输出**: `[]` - -### [示例 3] - -**输入**: `head = [7,7,7,7], val = 7` - -**输出**: `[]` - -### [约束] - -- 列表中的节点数目在范围 `[0, 10000]` 内 -- `1 <= Node.val <= 50` -- `0 <= val <= 50` - -## 思路 - -- 假设链表中待删除的节点是`d`,`d`的前一个节点是`p`,所以`p.next`就是`d`。 删除`d`,只需要把`p.next = p.next.next`。 - -- 因为用到了`p.next.next`,所以循环条件应为`while (p.next != null)`,而不是`while (p != null)`。 - -- 但`head`节点前面没有节点,这就意味着需要对`head`节点进行特殊处理。 - - 是否有方法能够让`head`节点的不再特殊呢?这样就不需要特殊处理`head`了。 - -
点击查看答案

办法是引入`dummy`节点,`dummy.next = head`。

- -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ -class Solution { - public ListNode removeElements(ListNode head, int val) { - var dummyHead = new ListNode(); - dummyHead.next = head; - var node = dummyHead; - - while (node.next != null) { - if (node.next.val == val) { - node.next = node.next.next; - } else { - node = node.next; - } - } - - return dummyHead.next; - } -} -``` - -## Python - -```python -# Definition for singly-linked list. -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]: - dummy_head = ListNode() - dummy_head.next = head - node = dummy_head - - while node.next: - if node.next.val == val: - node.next = node.next.next - else: - node = node.next - - return dummy_head.next -``` - -## C++ - -```cpp -/** - * Definition for singly-linked list. - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* removeElements(ListNode* head, int val) { - auto dummyHead = new ListNode(); - dummyHead->next = head; - auto node = dummyHead; - - while (node->next != nullptr) { - if (node->next->val == val) { - auto next_node = node->next; - node->next = node->next->next; - delete next_node; - } else { - node = node->next; - } - } - - return dummyHead->next; - } -}; -``` - -## JavaScript - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var removeElements = function (head, val) { - const dummyHead = new ListNode() - dummyHead.next = head - let node = dummyHead - - while (node.next != null) { - if (node.next.val == val) { - node.next = node.next.next - } else { - node = node.next - } - } - - return dummyHead.next -}; -``` - -## C# - -```csharp -/** - * Definition for singly-linked list. - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution { - public ListNode RemoveElements(ListNode head, int val) { - var dummyHead = new ListNode(); - dummyHead.next = head; - var node = dummyHead; - - while (node.next != null) { - if (node.next.val == val) { - node.next = node.next.next; - } else { - node = node.next; - } - } - - return dummyHead.next; - } -} -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func removeElements(head *ListNode, val int) *ListNode { - dummyHead := &ListNode{} - dummyHead.Next = head - node := dummyHead - - for node.Next != nil { - if node.Next.Val == val { - node.Next = node.Next.Next - } else { - node = node.Next - } - } - - return dummyHead.Next -} -``` - -## Ruby - -```ruby -# Definition for singly-linked list. -# class ListNode -# attr_accessor :val, :next -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def remove_elements(head, val) - dummy_head = ListNode.new - dummy_head.next = head - node = dummy_head - - until node.next.nil? - if node.next.val == val - node.next = node.next.next - else - node = node.next - end - end - - dummy_head.next -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[203. 移除链表元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/203-remove-linked-list-elements). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/206-reverse-linked-list.md b/zh/1-1000/206-reverse-linked-list.md deleted file mode 100644 index d6ec349..0000000 --- a/zh/1-1000/206-reverse-linked-list.md +++ /dev/null @@ -1,295 +0,0 @@ -# 206. 反转链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[206. 反转链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/206-reverse-linked-list),体验更佳! - -力扣链接:[206. 反转链表](https://leetcode.cn/problems/reverse-linked-list), 难度等级:**简单**。 - -## LeetCode “206. 反转链表”问题描述 - -给你单链表的头节点 `head` ,请你反转链表,并返回反转后的链表。 - -### [示例 1] - -![](../../images/examples/206_1.jpg) - -**输入**: `head = [1,2,3,4,5]` - -**输出**: `[5,4,3,2,1]` - -### [示例 2] - -![](../../images/examples/206_2.jpg) - -**输入**: `[1,2]` - -**输出**: `[2,1]` - -### [示例 3] - -**输入**: `[]` - -**输出**: `[]` - -### [约束] - -- 链表中节点的数目范围是 `[0, 5000]` -- `-5000 <= Node.val <= 5000` - -## 思路 - -1. 解决这个问题,只需要定义**两**个变量:`current`和`previous`。 - -
点击查看答案

`current.next = previous` 就是反转了。

- -2. 循环条件是`while (current != null)`,还是`while (current.next != null)`? - -
点击查看答案

是 `while (current != null)`,因为需要操作的是 `current.next = previous`。

- -## 步骤 - -1. 遍历所有节点。 - - ```javascript - previous = null - current = head - - while (current != null) { - current = current.next - } - ``` - -2. 加入`current.next = previous`。 - - ```javascript - previous = null - current = head - - while (current != null) { - tempNext = current.next - current.next = previous - current = tempNext - } - ``` - -3. `previous`目前始终是`null`,需要让它变化起来:`previous = current`。 - - ```javascript - previous = null - current = head - - while (current != null) { - tempNext = current.next - current.next = previous - previous = current - current = tempNext - } - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ -class Solution { - public ListNode reverseList(ListNode head) { - ListNode previous = null; - var current = head; - - while (current != null) { - var tempNext = current.next; - current.next = previous; - previous = current; - current = tempNext; - } - - return previous; - } -} -``` - -## Python - -```python -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: - previous = None - current = head - - while current: - temp_next = current.next - current.next = previous - previous = current - current = temp_next - - return previous -``` - -## C++ - -```cpp -/** - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* reverseList(ListNode* head) { - ListNode* previous = nullptr; - ListNode* current = head; - - while (current) { - auto temp_next = current->next; - current->next = previous; - previous = current; - current = temp_next; - } - - return previous; - } -}; -``` - -## JavaScript - -```javascript -/** - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var reverseList = function (head) { - let previous = null - let current = head - - while (current != null) { - const tempNext = current.next - current.next = previous - previous = current - current = tempNext - } - - return previous -}; -``` - -## C# - -```csharp -/** - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution -{ - public ListNode ReverseList(ListNode head) - { - ListNode previous = null; - ListNode current = head; - - while (current != null) - { - var tempNext = current.next; - current.next = previous; - previous = current; - current = tempNext; - } - - return previous; - } -} -``` - -## Go - -```go -/** - * Definition for singly-linked list. - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func reverseList(head *ListNode) *ListNode { - var previous *ListNode - current := head - - for current != nil { - tempNext := current.Next - current.Next = previous - previous = current - current = tempNext - } - - return previous -} -``` - -## Ruby - -```ruby -# class ListNode -# attr_accessor :val, :next -# -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def reverse_list(head) - previous = nil - current = head - - while current - temp_next = current.next - current.next = previous - previous = current - current = temp_next - end - - previous -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[206. 反转链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/206-reverse-linked-list). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/207-course-schedule.md b/zh/1-1000/207-course-schedule.md deleted file mode 100644 index 684d651..0000000 --- a/zh/1-1000/207-course-schedule.md +++ /dev/null @@ -1,430 +0,0 @@ -# 207. Course Schedule - Best Practices of LeetCode Solutions -LeetCode link: [207. Course Schedule](https://leetcode.com/problems/course-schedule) - -## LeetCode problem description -There are a total of `numCourses` courses you have to take, labeled from `0` to `numCourses - 1`. You are given an array `prerequisites` where `prerequisites[i] = [ai, bi]` indicates that you **must** take course `bi` first if you want to take course `ai`. - -* For example, the pair `[0, 1]`, indicates that to take course `0` you have to first take course `1`. - -Return `true` if you can finish all courses. Otherwise, return `false`. - -### Example 1 -```ruby -Input: numCourses = 2, prerequisites = [[1,0]] -Output: true -Explanation: There are a total of 2 courses to take. -To take course 1 you should have finished course 0. So it is possible. -``` - -### Example 2 -```ruby -Input: numCourses = 2, prerequisites = [[1,0],[0,1]] -Output: false -Explanation: There are a total of 2 courses to take. -To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible. -``` - -### Constraints -- `1 <= numCourses <= 2000` -- `0 <= prerequisites.length <= 5000` -- `prerequisites[i].length == 2` -- `0 <= ai, bi < numCourses` -- All the pairs `prerequisites[i]` are **unique**. - -## Intuition -- Each course can be abstracted as a vertex in a graph. -- The existence of a dependency relationship indicates that it is a directed graph. - -## Approach 1 -- Course A depends on course B, which can be abstracted as course A needs course B to unlock, and the in-degree of course A needs to be increased by 1. -- So an `in_degrees` array is needed to save the in-degree of each course. -- Courses with an in-degree of 0 can be studied first, so they can be put into a **queue** and processed one by one. -- Courses with an in-degree of 0 unlock other courses. This is the direction of the directed graph. Don't get it wrong. -- After each course is completed, the in-degree of other courses that depend on it is reduced by 1. If it is found that the in-degree of the course is 0 after deducting 1, the course is added to the queue. -- Which courses can be unlocked by a course need to be saved with a map or an array `courses_list`. -- If the in-degree of all courses is 0 at the end, return `true`, otherwise it means that there is a **cycle** in the directed graph, and return `false`. -- The above algorithm is a _breadth-first algorithm_. - -## Approach 2 -- Can you use a _depth-first algorithm_ to solve it? -- Simply replacing the queue used in the _breadth-first_ algorithm with a **stack** will create a _depth-first_ algorithm. - -## Complexity -`V` is `vertices.length`. - -`E` is `edges.length`. - -* Time: `O(V + E)`. -* Space: `O(V + E)`. - -## Python -### Solution 1: Breadth-First Search -```python -from collections import deque - -class Solution: - def canFinish(self, num_courses: int, prerequisites: List[List[int]]) -> bool: - courses_list = [set() for _ in range(num_courses)] # index: course, value: courses depend on course - in_degrees = [0] * num_courses - - for course_item, course in prerequisites: - courses_list[course].add(course_item) - in_degrees[course_item] += 1 - - ok_course_queue = deque( - [i for i, in_degree in enumerate(in_degrees) if in_degree == 0] - ) - - while ok_course_queue: - ok_course = ok_course_queue.popleft() - - for course in courses_list[ok_course]: - in_degrees[course] -= 1 - - if in_degrees[course] == 0: - ok_course_queue.append(course) - - return sum(in_degrees) == 0 -``` - -### Solution 2: Depth-First Search -```python -class Solution: - def canFinish(self, num_courses: int, prerequisites: List[List[int]]) -> bool: - courses_list = [set() for _ in range(num_courses)] # index: course, value: courses depend on course - in_degrees = [0] * num_courses - - for prerequisite in prerequisites: - courses_list[prerequisite[1]].add(prerequisite[0]) - in_degrees[prerequisite[0]] += 1 - - ok_courses = [i for i, in_degree in enumerate(in_degrees) if in_degree == 0] - - while ok_courses: - ok_course = ok_courses.pop() - - for course in courses_list[ok_course]: - in_degrees[course] -= 1 - - if in_degrees[course] == 0: - ok_courses.append(course) - - return sum(in_degrees) == 0 -``` - -## Java -### Solution 1: Breadth-First Search -```java -class Solution { - public boolean canFinish(int numCourses, int[][] prerequisites) { - var inDegrees = new int[numCourses]; - var coursesList = new ArrayList>(); // index: course, value: courses depend on course - for (var i = 0; i < numCourses; i++) { - coursesList.add(new HashSet()); - } - - for (var prerequisite : prerequisites) { - inDegrees[prerequisite[0]]++; - - var courses = coursesList.get(prerequisite[1]); - courses.add(prerequisite[0]); - } - - var okCourses = new ArrayDeque(); - var studiedCourseCount = 0; - - for (var course = 0; course < inDegrees.length; course++) { - if (inDegrees[course] == 0) { - okCourses.add(course); - } - } - - while (!okCourses.isEmpty()) { - var okCourse = okCourses.poll(); - studiedCourseCount++; - - for (var course : coursesList.get(okCourse)) { - inDegrees[course]--; - - if (inDegrees[course] == 0) { - okCourses.add(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -### Solution 2: Depth-First Search -```java -class Solution { - public boolean canFinish(int numCourses, int[][] prerequisites) { - var inDegrees = new int[numCourses]; - var coursesList = new ArrayList>(); // index: course, value: courses depend on course - for (var i = 0; i < numCourses; i++) { - coursesList.add(new HashSet()); - } - - for (var prerequisite : prerequisites) { - inDegrees[prerequisite[0]]++; - - var courses = coursesList.get(prerequisite[1]); - courses.add(prerequisite[0]); - } - - var okCourses = new Stack(); - var studiedCourseCount = 0; - - for (var course = 0; course < inDegrees.length; course++) { - if (inDegrees[course] == 0) { - okCourses.push(course); - } - } - - while (!okCourses.isEmpty()) { - var okCourse = okCourses.pop(); - studiedCourseCount++; - - for (var course : coursesList.get(okCourse)) { - inDegrees[course]--; - - if (inDegrees[course] == 0) { - okCourses.push(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -## C++ -### Solution 1: Breadth-First Search -```cpp -class Solution { -public: - bool canFinish(int num_courses, vector>& prerequisites) { - auto in_degrees = vector(num_courses); - auto courses_vector = vector>(num_courses); // index: course, value: courses depend on course - - for (auto& prerequisite : prerequisites) { - in_degrees[prerequisite[0]]++; - - courses_vector[prerequisite[1]].insert(prerequisite[0]); - } - - queue ok_courses; - auto studied_course_count = 0; - - for (auto course = 0; course < in_degrees.size(); course++) { - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - - while (!ok_courses.empty()) { - auto okCourse = ok_courses.front(); - ok_courses.pop(); - studied_course_count++; - - for (auto course : courses_vector[okCourse]) { - in_degrees[course]--; - - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - } - - return studied_course_count == num_courses; - } -}; -``` - -### Solution 2: Depth-First Search -```cpp -class Solution { -public: - bool canFinish(int num_courses, vector>& prerequisites) { - auto in_degrees = vector(num_courses); - auto courses_vector = vector>(num_courses); // index: course, value: courses depend on course - - for (auto& prerequisite : prerequisites) { - in_degrees[prerequisite[0]]++; - - courses_vector[prerequisite[1]].insert(prerequisite[0]); - } - - stack ok_courses; - auto studied_course_count = 0; - - for (auto course = 0; course < in_degrees.size(); course++) { - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - - while (!ok_courses.empty()) { - auto okCourse = ok_courses.top(); - ok_courses.pop(); - studied_course_count++; - - for (auto course : courses_vector[okCourse]) { - in_degrees[course]--; - - if (in_degrees[course] == 0) { - ok_courses.push(course); - } - } - } - - return studied_course_count == num_courses; - } -}; -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -### Solution 1: Breadth-First Search -```c# -public class Solution { - public bool CanFinish(int numCourses, int[][] prerequisites) - { - var inDegrees = new int[numCourses]; - var coursesList = new List>(); // index: course, value: courses depend on course - - for (int i = 0; i < numCourses; i++) - coursesList.Add(new HashSet()); - - foreach (int[] prerequisite in prerequisites) - { - inDegrees[prerequisite[0]]++; - - var courses = coursesList[prerequisite[1]]; - courses.Add(prerequisite[0]); - } - - var okCourses = new Queue(); - int studiedCourseCount = 0; - - for (int course = 0; course < inDegrees.Length; course++) - { - if (inDegrees[course] == 0) - { - okCourses.Enqueue(course); - } - } - - while (okCourses.Count > 0) - { - int okCourse = okCourses.Dequeue(); - studiedCourseCount++; - - foreach (int course in coursesList[okCourse]) - { - inDegrees[course]--; - - if (inDegrees[course] == 0) - { - okCourses.Enqueue(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -### Solution 2: Depth-First Search -```c# -public class Solution { - public bool CanFinish(int numCourses, int[][] prerequisites) - { - var inDegrees = new int[numCourses]; - var coursesList = new List>(); // index: course, value: courses depend on course - - for (int i = 0; i < numCourses; i++) - coursesList.Add(new HashSet()); - - foreach (int[] prerequisite in prerequisites) - { - inDegrees[prerequisite[0]]++; - - var courses = coursesList[prerequisite[1]]; - courses.Add(prerequisite[0]); - } - - var okCourses = new Stack(); - int studiedCourseCount = 0; - - for (int course = 0; course < inDegrees.Length; course++) - { - if (inDegrees[course] == 0) - { - okCourses.Push(course); - } - } - - while (okCourses.Count > 0) - { - int okCourse = okCourses.Pop(); - studiedCourseCount++; - - foreach (int course in coursesList[okCourse]) - { - inDegrees[course]--; - - if (inDegrees[course] == 0) - { - okCourses.Push(course); - } - } - } - - return studiedCourseCount == numCourses; - } -} -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/209-minimum-size-subarray-sum.md b/zh/1-1000/209-minimum-size-subarray-sum.md deleted file mode 100644 index dd2236e..0000000 --- a/zh/1-1000/209-minimum-size-subarray-sum.md +++ /dev/null @@ -1,301 +0,0 @@ -# 209. 长度最小的子数组 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[209. 长度最小的子数组 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/209-minimum-size-subarray-sum),体验更佳! - -力扣链接:[209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum), 难度等级:**中等**。 - -## LeetCode “209. 长度最小的子数组”问题描述 - -给定一个含有 `n` 个正整数的数组和一个正整数 `target` 。 - -找出该数组中满足其总和大于等于 `target` 的长度**最小的** **子数组** `[numsl, numsl+1, ..., numsr-1, numsr]` ,并返回*其长度*。如果不存在符合条件的子数组,返回 `0` 。 - -> **子数组** 是数组中连续的 **非空** 元素序列。 - -### [示例 1] - -**输入**: `target = 7, nums = [2,3,1,2,4,3]` - -**输出**: `2` - -**解释**: `子数组 [4,3] 是该条件下的长度最小的子数组。` - -### [示例 2] - -**输入**: `target = 4, nums = [1,4,4]` - -**输出**: `1` - -**解释**: `target = 11, nums = [1,1,1,1,1,1,1,1]` - -### [示例 3] - -**输入**: `target = 11, nums = [1,1,1,1,1,1,1,1]` - -**输出**: `0` - -### [约束] - -- `1 <= target <= 10^9` -- `1 <= nums.length <= 10^5` -- `1 <= nums[i] <= 10^4` - -## 思路 - -1. 对于**子数组**问题,可以考虑使用**滑动窗口技术**,它类似于**快慢双指针方法**。 - -## 步骤 - -1. **遍历** `nums` 数组,元素的 `index` 可命名为 `fastIndex`。虽然不起眼,但这是 `快慢指针技术` **最重要**的逻辑。请最好记住它。 - -2. `sum += nums[fast_index]`. - - ```java - var minLength = Integer.MAX_VALUE; - var sum = 0; - var slowIndex = 0; - - for (var fastIndex = 0; fastIndex < nums.length; fastIndex++) { // 本行是`快慢指针技术`最重要的逻辑 - sum += nums[fastIndex]; // 1 - } - - return minLength; - ``` - -3. 控制`slowIndex`。 - - ```java - var minLength = Integer.MAX_VALUE; - var sum = 0; - var slowIndex = 0; - - for (var fastIndex = 0; fastIndex < nums.length; fastIndex++) { - sum += nums[fastIndex]; - - while (sum >= target) { // 1 - minLength = Math.min(minLength, fastIndex - slowIndex + 1); // 2 - sum -= nums[slowIndex]; // 3 - slowIndex++; // 4 - } - } - - if (minLength == Integer.MAX_VALUE) { // 5 - return 0; // 6 - } - - return minLength; - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -class Solution { - public int minSubArrayLen(int target, int[] nums) { - var minLength = Integer.MAX_VALUE; - var sum = 0; - var slowIndex = 0; - - for (var fastIndex = 0; fastIndex < nums.length; fastIndex++) { // This line is the most important. You'd better memorize it. - sum += nums[fastIndex]; - - while (sum >= target) { - minLength = Math.min(minLength, fastIndex - slowIndex + 1); - sum -= nums[slowIndex]; - slowIndex++; - } - } - - if (minLength == Integer.MAX_VALUE) { - return 0; - } - - return minLength; - } -} -``` - -## Python - -```python -class Solution: - def minSubArrayLen(self, target: int, nums: List[int]) -> int: - min_length = float('inf') - sum_ = 0 - slow_index = 0 - - for fast_index, num in enumerate(nums): # This line is the most important. You'd better memorize it. - sum_ += num - - while sum_ >= target: - min_length = min(min_length, fast_index - slow_index + 1) - sum_ -= nums[slow_index] - slow_index += 1 - - if min_length == float('inf'): - return 0 - - return min_length -``` - -## JavaScript - -```javascript -var minSubArrayLen = function (target, nums) { - let minLength = Number.MAX_SAFE_INTEGER - let sum = 0 - let slowIndex = 0 - - nums.forEach((num, fastIndex) => { // This line is the most important. You'd better memorize it. - sum += num - - while (sum >= target) { - minLength = Math.min(minLength, fastIndex - slowIndex + 1) - sum -= nums[slowIndex] - slowIndex++ - } - }) - - if (minLength == Number.MAX_SAFE_INTEGER) { - return 0 - } - - return minLength -}; -``` - -## C# - -```csharp -public class Solution -{ - public int MinSubArrayLen(int target, int[] nums) - { - int minLength = Int32.MaxValue; - int sum = 0; - int slowIndex = 0; - - for (int fastIndex = 0; fastIndex < nums.Length; fastIndex++) // This line is the most important. You'd better memorize it. - { - sum += nums[fastIndex]; - - while (sum >= target) - { - minLength = Math.Min(minLength, fastIndex - slowIndex + 1); - sum -= nums[slowIndex]; - slowIndex++; - } - } - - if (minLength == Int32.MaxValue) - return 0; - - return minLength; - } -} -``` - -## Go - -```go -func minSubArrayLen(target int, nums []int) int { - minLength := math.MaxInt32 - sum := 0 - slowIndex := 0 - - for fastIndex := 0; fastIndex < len(nums); fastIndex++ { // This line is the most important. You'd better memorize it. - sum += nums[fastIndex] - - for sum >= target { - minLength = min(minLength, fastIndex - slowIndex + 1) - sum -= nums[slowIndex] - slowIndex++ - } - } - - if minLength == math.MaxInt32 { - return 0 - } - - return minLength -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} -``` - -## Ruby - -```ruby -# @param {Integer} target -# @param {Integer[]} nums -# @return {Integer} -def min_sub_array_len(target, nums) - min_length = Float::INFINITY - sum = 0 - slow_index = 0 - - nums.each_with_index do |num, fast_index| # This line is the most important. You'd better memorize it. - sum += num - - while sum >= target - min_length = [min_length, fast_index - slow_index + 1].min - sum -= nums[slow_index] - slow_index += 1 - end - end - - min_length == Float::INFINITY ? 0 : min_length -end -``` - -## C++ - -```cpp -class Solution { -public: - int minSubArrayLen(int target, vector& nums) { - int min_length = INT_MAX; - int sum = 0; - int slow_index = 0; - - for (int fast_index = 0; fast_index < nums.size(); fast_index++) { - sum += nums[fast_index]; - - while (sum >= target) { - min_length = min(min_length, fast_index - slow_index + 1); - sum -= nums[slow_index]; - slow_index++; - } - } - - if (min_length == INT_MAX) { - return 0; - } - - return min_length; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[209. 长度最小的子数组 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/209-minimum-size-subarray-sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/213-house-robber-ii.md b/zh/1-1000/213-house-robber-ii.md deleted file mode 100644 index a7f5d4b..0000000 --- a/zh/1-1000/213-house-robber-ii.md +++ /dev/null @@ -1,149 +0,0 @@ -# 213. House Robber II -LeetCode link: [213. House Robber II](https://leetcode.com/problems/house-robber-ii/) - -## LeetCode problem description -You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are **arranged in a circle**. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and **it will automatically contact the police if two adjacent houses were broken into on the same night**. - -Given an integer array `nums` representing the amount of money of each house, return the maximum amount of money you can rob tonight **without alerting the police**. - -``` ----------------------------------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [2,3,2] -Output: 3 -Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses. ----------------------------------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [1,2,3,1] -Output: 4 -Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). - Total amount you can rob = 1 + 3 = 4. ----------------------------------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums = [1,2,3] -Output: 3 ----------------------------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 100 -0 <= nums[i] <= 1000 ----------------------------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Solution 1 -```python -class Solution: - def rob(self, nums: List[int]) -> int: - if len(nums) <= 2: - return max(nums) - - return max( - max_money_robbed(nums[1:]), - max_money_robbed(nums[:-1]) - ) - -def max_money_robbed(nums): - dp = [0] * len(nums) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i in range(2, len(dp)): - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - - return dp[-1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var rob = function (nums) { - if (nums.length <= 2) { - return Math.max(...nums) - } - - return Math.max( - maxMoneyRobbed(nums.slice(1,)), - maxMoneyRobbed(nums.slice(0, nums.length - 1)) - ) -}; - -var maxMoneyRobbed = function (nums) { - const dp = Array(nums.length).fill(0) - dp[0] = nums[0] - dp[1] = Math.max(nums[0], nums[1]) - - for (let i = 2; i < dp.length; i++) { - dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp.at(-1) -}; -``` - -## Go -```go -func rob(nums []int) int { - if len(nums) <= 2 { - return slices.Max(nums) - } - - return max( - maxMoneyRobbed(nums[1:]), - maxMoneyRobbed(nums[:len(nums) - 1]), - ) -} - -func maxMoneyRobbed(nums []int) int { - dp := make([]int, len(nums)) - dp[0] = nums[0] - dp[1] = max(nums[0], nums[1]) - - for i := 2; i < len(dp); i++ { - dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/225-implement-stack-using-queues.md b/zh/1-1000/225-implement-stack-using-queues.md deleted file mode 100644 index b17cd66..0000000 --- a/zh/1-1000/225-implement-stack-using-queues.md +++ /dev/null @@ -1,711 +0,0 @@ -# 225. 用队列实现栈 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[225. 用队列实现栈 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/225-implement-stack-using-queues),体验更佳! - -力扣链接:[225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues), 难度等级:**简单**。 - -## LeetCode “225. 用队列实现栈”问题描述 - -请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(`push`、`top`、`pop` 和 `empty`)。 - -实现 `MyStack` 类: - -- `void push(int x)` 将元素 `x` 压入栈顶。 -- `int pop()` 移除并返回栈顶元素。 -- `int top()` 返回栈顶元素。 -- `boolean empty()` 如果栈是空的,返回 `true`;否则,返回 `false`。 - -**注意**: - -- 你只能使用队列的标准操作 —— 也就是 `push to back`、`peek/pop from front`、`size` 和 `is empty` 这些操作。 -- 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 - -### [示例 1] - -**输入**: `["MyStack", "push", "push", "top", "pop", "empty"] [[], [1], [2], [], [], []]` - -**输出**: `[null, null, null, 2, 2, false]` - -**解释**: - -

MyStack myStack = new MyStack();
-myStack.push(1);
-myStack.push(2);
-myStack.top(); // return 2
-myStack.pop(); // return 2
-myStack.empty(); // return False

- - -### [约束] - -- `1 <= x <= 9` -- 最多调用 `100` 次 `push`、`pop`、`top` 和 `empty` -- 每次调用 `pop` 和 `top` 都保证栈不为空 - -**进阶**:你能否仅用一个队列来实现栈。 - -## 思路 1 - -1. 使用的两个队列,一个队列用于输入和输出,另一个队列用于临时存储。 -2. 用队列模拟栈的功能,有两种方案可供选择: - 1. 方案一:简化`pop()`和`top()`操作,复杂化`push(x)`操作。`push(x)`时,需要费力地把`x`插入到队列头部。 - 2. 方案二:简化`push(x)`操作,复杂化`pop()`和`top()`操作。`pop()`或`top()`时,需要费力找到最后一个数据。 -3. 方案一优点:代码量更少,因为它只需要复杂化一个方法,而方案二要复杂化两个方法;从逻辑上更容易理解,因为它把队列中的数据按`后入先出`的规则排好序了。 - -## 复杂度 - -- 时间复杂度: `push O(n), pop O(1), top O(1), empty O(1)`. -- 空间复杂度: `O(n)`. - -## Python - -```python -class MyStack: - def __init__(self): - self.queue = deque() - self.queue_temp = deque() - - def push(self, x: int) -> None: - # Move all 'queue' items to 'queue_temp'. - while self.queue: - self.queue_temp.append( - self.queue.popleft() - ) - - # Emplaced 'x' at the first of 'queue' because 'queue' is empty. - self.queue.append(x) - - # Move all 'queue_temp' items back to 'queue'. - while self.queue_temp: - self.queue.append( - self.queue_temp.popleft() - ) - - def pop(self) -> int: - return self.queue.popleft() - - def top(self) -> int: - return self.queue[0] - - def empty(self) -> bool: - return not self.queue -``` - -## C++ - -```cpp -class MyStack { -private: - queue queue_; - queue queue_temp_; - -public: - MyStack() {} - - void push(int x) { - // Step 1: Move all existing elements from main queue_ to temp_queue_ - while (!queue_.empty()) { - queue_temp_.push(queue_.front()); - queue_.pop(); - } - - // Step 2: Add the new element to the now-empty main queue_ - // This ensures the newest element is at the front (LIFO behavior) - queue_.push(x); - - // Step 3: Move all elements from temp_queue_ back to main queue_ - // This places all previous elements behind the new element - while (!queue_temp_.empty()) { - queue_.push(queue_temp_.front()); - queue_temp_.pop(); - } - } - - int pop() { - int val = queue_.front(); - queue_.pop(); - return val; - } - - int top() { return queue_.front(); } - - bool empty() { return queue_.empty(); } -}; -``` - -## Go - -```go -type MyStack struct { - // Main queue that stores elements in stack order - queue []int - // Temporary queue used during push operations - queueTemp []int -} - -func Constructor() MyStack { - return MyStack{ - queue: []int{}, - queueTemp: []int{}, - } -} - -func (this *MyStack) Push(x int) { - // Step 1: Move all existing elements from main queue to temp queue - for len(this.queue) > 0 { - // Remove from front and add to temp queue - this.queueTemp = append(this.queueTemp, this.queue[0]) - this.queue = this.queue[1:] - } - - // Step 2: Add the new element to the now-empty main queue - // This ensures the newest element is at the front (LIFO behavior) - this.queue = append(this.queue, x) - - // Step 3: Move all elements from temp queue back to main queue - // This places all previous elements behind the new element - for len(this.queueTemp) > 0 { - // Remove from front and add to main queue - this.queue = append(this.queue, this.queueTemp[0]) - this.queueTemp = this.queueTemp[1:] - } -} - -func (this *MyStack) Pop() int { - val := this.queue[0] - this.queue = this.queue[1:] - return val -} - -func (this *MyStack) Top() int { - return this.queue[0] -} - -func (this *MyStack) Empty() bool { - return len(this.queue) == 0 -} -``` - -## Ruby - -```ruby -class MyStack - def initialize - @queue = [] # Main queue that stores elements in stack order - @queue_temp = [] # Temporary queue used during push operations - end - - def push(x) - # Step 1: Move all existing elements from main queue to temp queue - while !@queue.empty? - @queue_temp.push(@queue.shift) - end - - # Step 2: Add the new element to the now-empty main queue - # This ensures the newest element is at the front (LIFO behavior) - @queue.push(x) - - # Step 3: Move all elements from temp queue back to main queue - # This places all previous elements behind the new element - while !@queue_temp.empty? - @queue.push(@queue_temp.shift) - end - end - - def pop - @queue.shift - end - - def top - @queue.first - end - - def empty - @queue.empty? - end -end -``` - -## JavaScript - -```javascript -var MyStack = function () { - this.queue = [] - this.queueTemp = [] -}; - -MyStack.prototype.push = function (x) { - while (this.queue.length > 0) { - this.queueTemp.push( - this.queue.shift() // remove from head - ) - } - - this.queue.push(x) - - while (this.queueTemp.length > 0) { - this.queue.push( - this.queueTemp.shift() // remove from head - ) - } -}; - -MyStack.prototype.pop = function () { - return this.queue.shift() // remove from head -}; - -MyStack.prototype.top = function () { - return this.queue[0] -}; - -MyStack.prototype.empty = function () { - return this.queue.length === 0 -}; -``` - -## Java - -```java -class MyStack { - private Queue queue; - private Queue queueTemp; - - public MyStack() { - queue = new LinkedList<>(); // main queue - queueTemp = new LinkedList<>(); - } - - public void push(int x) { - // Move all elements from main queue to temporary queue - while (!queue.isEmpty()) { - queueTemp.offer( - queue.poll() // Remove from front (standard queue operation) - ); - } - - // Add the new element to the now-empty main queue - // This will be the first element to be removed (stack's top) - queue.offer(x); - - // Move all elements back from temporary queue to main queue - // This ensures newest elements are at the front of the queue - while (!queueTemp.isEmpty()) { - queue.offer( - queueTemp.poll() // Remove from front (standard queue operation) - ); - } - } - - public int pop() { - return queue.poll(); - } - - public int top() { - return queue.peek(); - } - - public boolean empty() { - return queue.isEmpty(); - } -} -``` - -## C# - -```csharp -public class MyStack -{ - private Queue queue; // main queue - private Queue queueTemp; - - public MyStack() - { - queue = new Queue(); - queueTemp = new Queue(); - } - - public void Push(int x) - { - // Move all elements from main queue to temporary queue - while (queue.Count > 0) - { - queueTemp.Enqueue( - queue.Dequeue() - ); - } - - // Add the new element to the now-empty main queue - // This will be the first element to be removed (stack's top) - queue.Enqueue(x); - - // Move all elements back from temporary queue to main queue - // This ensures newest elements are at the front of the queue - while (queueTemp.Count > 0) - { - queue.Enqueue( - queueTemp.Dequeue() - ); - } - } - - public int Pop() - { - return queue.Dequeue(); - } - - public int Top() - { - return queue.Peek(); - } - - public bool Empty() - { - return queue.Count == 0; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -1. 使用的两个队列,一个队列用于输入和输出,另一个队列用于临时存储。 -2. 用队列模拟栈的功能,有两种方案可供选择: - 1. 方案一:简化`pop()`和`top()`操作,复杂化`push(x)`操作。`push(x)`时,需要费力地把`x`插入到队列头部。 - 2. 方案二:简化`push(x)`操作,复杂化`pop()`和`top()`操作。`pop()`或`top()`时,需要费力找到最后一个数据。 -3. 本文主要介绍`方案二`,方便读者对比这两个方案。 - -## 复杂度 - -- 时间复杂度: `push O(1), pop O(n), top O(n), empty O(1)`. -- 空间复杂度: `O(n)`. - -## Python - -```python -class MyStack: - def __init__(self): - self.queue = deque() - self.queue_temp = deque() - - def push(self, x: int) -> None: - self.queue.append(x) - - def pop(self) -> int: - while len(self.queue) > 1: - self.queue_temp.append( - self.queue.popleft() - ) - - value = self.queue.popleft() - - while self.queue_temp: - self.queue.append( - self.queue_temp.popleft() - ) - - return value - - def top(self) -> int: - value = None - - while self.queue: - value = self.queue.popleft() - self.queue_temp.append(value) - - while self.queue_temp: - self.queue.append( - self.queue_temp.popleft() - ) - - return value - - def empty(self) -> bool: - return not self.queue -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 3 - -- 可以只用一个队列实现栈。改动只在`push`方法。只需要想办法不借助另一个`queue_temp`,把`x`插入到队列的头部。 -- 在实现`push`方法时,先`queue.push(x)`,这样,`x`就被插入到了队列尾部,但我们需要把`x`放到队列的头部。 -- 把`x`前面的所有数据依次出队列,再入队列,就可以了。 -- 执行`queue.length - 1`次`queue.push(queue.pop())`即可。 - -## 复杂度 - -- 时间复杂度: `push O(n), pop O(1), top O(1), empty O(1)`. -- 空间复杂度: `O(n)`. - -## JavaScript - -```javascript -var MyStack = function () { - this.queue = [] -}; - -MyStack.prototype.push = function (x) { - this.queue.push(x) - - _.times( - this.queue.length - 1, - () => this.queue.push(this.queue.shift()) - ) -}; - -MyStack.prototype.pop = function () { - return this.queue.shift() -}; - -MyStack.prototype.top = function () { - return this.queue[0] -}; - -MyStack.prototype.empty = function () { - return this.queue.length === 0 -}; -``` - -## Python - -```python -from collections import deque - - -class MyStack: - def __init__(self): - self.queue = deque() - - def push(self, x: int) -> None: - self.queue.append(x) - - # Rotate the queue to put the new element at the front - # This is done by moving all existing elements to the back - for _ in range(len(self.queue) - 1): - self.queue.append( - self.queue.popleft() - ) - - def pop(self) -> int: - return self.queue.popleft() - - def top(self) -> int: - return self.queue[0] - - def empty(self) -> bool: - return not self.queue -``` - -## C++ - -```cpp -class MyStack { -private: - queue q_; - -public: - MyStack() {} - - void push(int x) { - q_.push(x); - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for (int i = 0; i < q_.size() - 1; i++) { - q_.push(q_.front()); // Add front element to back - q_.pop(); // Remove from front - } - } - - int pop() { - int top = q_.front(); - q_.pop(); - return top; - } - - int top() { - return q_.front(); - } - - bool empty() { - return q_.empty(); - } -}; -``` - -## Go - -```go -type MyStack struct { - queue []int -} - -func Constructor() MyStack { - return MyStack{ - queue: make([]int, 0), - } -} - -func (this *MyStack) Push(x int) { - // Add the new element to the queue - this.queue = append(this.queue, x) - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for i := 0; i < len(this.queue) - 1; i++ { - // Move first element to the back - this.queue = append(this.queue, this.queue[0]) - this.queue = this.queue[1:] - } -} - -func (this *MyStack) Pop() int { - // Remove and return the first element (stack's top) - top := this.queue[0] - this.queue = this.queue[1:] - return top -} - -func (this *MyStack) Top() int { - return this.queue[0] -} - -func (this *MyStack) Empty() bool { - return len(this.queue) == 0 -} -``` - -## Ruby - -```ruby -class MyStack - def initialize - @queue = [] - end - - def push(x) - @queue.push(x) - - # Rotate the queue to put the new element at the front - # This is done by moving all existing elements to the back - (@queue.length - 1).times do - @queue.push(@queue.shift) # Move first element to the back - end - end - - def pop - @queue.shift - end - - def top - @queue.first - end - - def empty - @queue.empty? - end -end -``` - -## Java - -```java -import java.util.LinkedList; -import java.util.Queue; - -class MyStack { - private Queue queue; - - public MyStack() { - queue = new LinkedList<>(); - } - - public void push(int x) { - queue.offer(x); - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for (int i = 0; i < queue.size() - 1; i++) { - queue.offer(queue.poll()); // Move first element to the back - } - } - - public int pop() { - return queue.poll(); - } - - public int top() { - return queue.peek(); - } - - public boolean empty() { - return queue.isEmpty(); - } -} -``` - -## C# - -```csharp -using System.Collections.Generic; - -public class MyStack -{ - private Queue queue; - - public MyStack() - { - queue = new Queue(); - } - - public void Push(int x) - { - queue.Enqueue(x); - - // Rotate the queue to put the new element at the front - // This is done by moving all existing elements to the back - for (int i = 0; i < queue.Count - 1; i++) - { - queue.Enqueue(queue.Dequeue()); // Move first element to the back - } - } - - public int Pop() - { - return queue.Dequeue(); - } - - public int Top() - { - return queue.Peek(); - } - - public bool Empty() - { - return queue.Count == 0; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[225. 用队列实现栈 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/225-implement-stack-using-queues). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/232-implement-queue-using-stacks.md b/zh/1-1000/232-implement-queue-using-stacks.md deleted file mode 100644 index 710daff..0000000 --- a/zh/1-1000/232-implement-queue-using-stacks.md +++ /dev/null @@ -1,357 +0,0 @@ -# 232. 用栈实现队列 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[232. 用栈实现队列 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/232-implement-queue-using-stacks),体验更佳! - -力扣链接:[232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks), 难度等级:**简单**。 - -## LeetCode “232. 用栈实现队列”问题描述 - -请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(`push`、`pop`、`peek`、`empty`): - -实现 `MyQueue` 类: - -- `void push(int x)` 将元素 `x` 推到队列的末尾 -- `int pop()` 从队列的开头移除并返回元素 -- `int peek()` 返回队列开头的元素 -- `boolean empty()` 如果队列为空,返回 `true` ;否则,返回 `false` - -**说明:** - -你 **只能** 使用标准的栈操作 —— 也就是只有 `push to top`, `peek/pop from top`, `size`, 和 `is empty` 操作是合法的。 -你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 - -### [示例 1] - -**输入**: `["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []]` - -**输出**: `[null, null, null, 1, 1, false]` - -**解释**: - -

MyQueue myQueue = new MyQueue();
-myQueue.push(1); // queue is: [1]
-myQueue.push(2); // queue is: 1, 2
-myQueue.peek(); // return 1
-myQueue.pop(); // return 1, queue is [2]
-myQueue.empty(); // return false

- - -### [约束] - -- `1 <= x <= 9` -- 最多调用 `100` 次 `push`、`pop`、`peek` 和 `empty` -- 假设所有操作都是有效的 (例如,一个空的队列不会调用 `pop` 或者 `peek` 操作) - - -**进阶:** 你能否实现每个操作均摊时间复杂度为 `O(1)` 的队列?换句话说,执行 `n` 个操作的总时间复杂度为 `O(n)` ,即使其中一个操作可能花费较长时间。 - -## 思路 - -- 用两个栈实现一个队列,直觉的想法是一个栈`stack_in`专门用于`push`,另一个栈`stack_out`专门用于`pop`。 - -- `push`可以很容易,直接`push`就好了,这样`pop`就没有那么容易了。如何做呢? -
点击查看答案

栈是后进先出,队列是先进先出,二者是相反的,所以直接从`stack_in`中`pop`是不行的,得把`stack_in`中的元素反向加到`stack_out`中,再`pop`。

- -## 复杂度 - -> `pop` 和 `peek` 看起来是 `O(n)`,实际是`O(1)`。因为如果一次`dump_into_stack_out`操作了`m`个数,之后的`m`次,每次`pop`都是`O(1)`。 - -- 时间复杂度: `push O(1), pop O(1), peek O(1), empty O(1)`. -- 空间复杂度: `O(n)`. - -## Python - -```python -class MyQueue: - def __init__(self): - self.stack_in = [] - self.stack_out = [] - - def push(self, x: int) -> None: - self.stack_in.append(x) - - def pop(self) -> int: - self.dump_into_stack_out_if_it_is_empty() - return self.stack_out.pop() - - def peek(self) -> int: - self.dump_into_stack_out_if_it_is_empty() - return self.stack_out[-1] - - def empty(self) -> bool: - return not self.stack_out and not self.stack_in - - def dump_into_stack_out_if_it_is_empty(self) -> int: - if not self.stack_out: - while self.stack_in: - self.stack_out.append(self.stack_in.pop()) -``` - -## JavaScript - -```javascript -var MyQueue = function () { - this.stackIn = [] - this.stackOut = [] -}; - -MyQueue.prototype.push = function (x) { - this.stackIn.push(x) -}; - -MyQueue.prototype.pop = function () { - this.dumpIntoStackOutWhenItIsEmpty() - return this.stackOut.pop() -}; - -MyQueue.prototype.peek = function () { - this.dumpIntoStackOutWhenItIsEmpty() - return this.stackOut.at(-1) -}; - -MyQueue.prototype.empty = function () { - return this.stackOut.length === 0 && this.stackIn.length === 0 -}; - -MyQueue.prototype.dumpIntoStackOutWhenItIsEmpty = function () { - if (this.stackOut.length === 0) { - while (this.stackIn.length > 0) { - this.stackOut.push(this.stackIn.pop()) - } - } -} -``` - -## Java - -```java -import java.util.Stack; - -class MyQueue { - private Stack stackIn; - private Stack stackOut; - - public MyQueue() { - stackIn = new Stack<>(); - stackOut = new Stack<>(); - } - - public void push(int x) { - stackIn.push(x); - } - - public int pop() { - dumpIntoStackOutWhenItIsEmpty(); - return stackOut.pop(); - } - - public int peek() { - dumpIntoStackOutWhenItIsEmpty(); - return stackOut.peek(); - } - - public boolean empty() { - return stackIn.empty() && stackOut.empty(); - } - - private void dumpIntoStackOutWhenItIsEmpty() { - if (stackOut.empty()) { - while (!stackIn.empty()) { - stackOut.push(stackIn.pop()); - } - } - } -} -``` - -## C++ - -```cpp -class MyQueue { -private: - stack stack_in_; - stack stack_out_; - - void dumpIntoStackOutWhenItIsEmpty() { - if (stack_out_.empty()) { - while (!stack_in_.empty()) { - stack_out_.push(stack_in_.top()); - stack_in_.pop(); - } - } - } - -public: - MyQueue() {} - - void push(int x) { - stack_in_.push(x); - } - - int pop() { - dumpIntoStackOutWhenItIsEmpty(); - int value = stack_out_.top(); - stack_out_.pop(); - return value; - } - - int peek() { - dumpIntoStackOutWhenItIsEmpty(); - return stack_out_.top(); - } - - bool empty() { - return stack_in_.empty() && stack_out_.empty(); - } -}; -``` - -## C# - -```csharp -using System.Collections.Generic; - -public class MyQueue -{ - private Stack stackIn; - private Stack stackOut; - - public MyQueue() - { - stackIn = new Stack(); - stackOut = new Stack(); - } - - public void Push(int x) - { - stackIn.Push(x); - } - - public int Pop() - { - DumpIntoStackOutWhenItIsEmpty(); - return stackOut.Pop(); - } - - public int Peek() - { - DumpIntoStackOutWhenItIsEmpty(); - return stackOut.Peek(); - } - - public bool Empty() - { - return stackIn.Count == 0 && stackOut.Count == 0; - } - - private void DumpIntoStackOutWhenItIsEmpty() - { - if (stackOut.Count == 0) - { - while (stackIn.Count > 0) - { - stackOut.Push(stackIn.Pop()); - } - } - } -} -``` - -## Go - -```go -type MyQueue struct { - stackIn []int - stackOut []int -} - -func Constructor() MyQueue { - return MyQueue{ - stackIn: make([]int, 0), - stackOut: make([]int, 0), - } -} - -func (this *MyQueue) Push(x int) { - this.stackIn = append(this.stackIn, x) -} - -func (this *MyQueue) Pop() int { - this.dumpIntoStackOutWhenItIsEmpty() - top := this.stackOut[len(this.stackOut) - 1] - this.stackOut = this.stackOut[:len(this.stackOut) - 1] - return top -} - -func (this *MyQueue) Peek() int { - this.dumpIntoStackOutWhenItIsEmpty() - return this.stackOut[len(this.stackOut) - 1] -} - -func (this *MyQueue) Empty() bool { - return len(this.stackIn) == 0 && len(this.stackOut) == 0 -} - -func (this *MyQueue) dumpIntoStackOutWhenItIsEmpty() { - if len(this.stackOut) == 0 { - for len(this.stackIn) > 0 { - top := this.stackIn[len(this.stackIn) - 1] - this.stackIn = this.stackIn[:len(this.stackIn) - 1] - this.stackOut = append(this.stackOut, top) - } - } -} -``` - -## Ruby - -```ruby -class MyQueue - def initialize - @stack_in = [] - @stack_out = [] - end - - def push(x) - @stack_in.push(x) - end - - def pop - dump_into_stack_out_when_it_is_empty - @stack_out.pop - end - - def peek - dump_into_stack_out_when_it_is_empty - @stack_out.last - end - - def empty - @stack_in.empty? && @stack_out.empty? - end - - private - - def dump_into_stack_out_when_it_is_empty - if @stack_out.empty? - while !@stack_in.empty? - @stack_out.push(@stack_in.pop) - end - end - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[232. 用栈实现队列 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/232-implement-queue-using-stacks). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/238-product-of-array-except-self.md b/zh/1-1000/238-product-of-array-except-self.md deleted file mode 100644 index abb2a3b..0000000 --- a/zh/1-1000/238-product-of-array-except-self.md +++ /dev/null @@ -1,550 +0,0 @@ -# 238. 除自身以外数组的乘积 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[238. 除自身以外数组的乘积 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/238-product-of-array-except-self),体验更佳! - -力扣链接:[238. 除自身以外数组的乘积](https://leetcode.cn/problems/product-of-array-except-self), 难度等级:**中等**。 - -## LeetCode “238. 除自身以外数组的乘积”问题描述 - -给你一个整数数组 `nums`,返回 数组 `answer` ,其中 `answer[i]` 等于 `nums` 中除 `nums[i]` 之外其余各元素的乘积 。 - -题目数据 **保证** 数组 `nums` 之中任意元素的全部前缀元素和后缀的乘积都在 **32 位** 整数范围内。 - -请 **不要使用除法**,且在 `O(n)` 时间复杂度内完成此题。 - -### [示例 1] - -**输入**: `nums = [1,2,3,4]` - -**输出**: `[24,12,8,6]` - -### [示例 2] - -**输入**: `nums = [-1,1,0,-3,3]` - -**输出**: `[0,0,9,0,0]` - -### [约束] - -- `2 <= nums.length <= 10^5` -- `-30 <= nums[i] <= 30` -- 输入 **保证** 数组 `answer[i]` 在 **32 位** 整数范围内 - - -**进阶**:你可以在 `O(1)` 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 **不被视为** 额外空间。) - -### [Hints] - -
- 提示 1 - Think how you can efficiently utilize prefix and suffix products to calculate the product of all elements except self for each index. Can you pre-compute the prefix and suffix products in linear time to avoid redundant calculations? - - - -
- -
- 提示 2 - Can you minimize additional space usage by reusing memory or modifying the input array to store intermediate results? - - -
- -## 思路 1 - -1. **分解问题**:将"除自身外的乘积"分解为"左侧乘积 × 右侧乘积" -2. **两次遍历**:先计算每个元素的左侧乘积,再计算右侧乘积 -3. **合并结果**:将左右乘积相乘得到最终结果 - -## “预计算技术”的模式 - -**预计算技术(Pre-Computation Techniques)** 是一种通过提前计算并存储中间结果或常用数据,以减少实时计算开销的优化方法。其核心思想是**“用空间换时间”**。 - -#### 主要应用场景 - -- **数组的前缀/后缀**计算问题。 -- **高频计算问题**:如斐波那契数列、阶乘、素数表等,通过预先生成查找表(Lookup Table)避免重复计算。 -- **动态规划(DP)**:预先计算子问题的解并存储,如背包问题、最短路径问题。 - -## 步骤 - -1. **初始化数组**: - - 创建`leftProducts`数组,存储每个元素左侧所有元素的乘积 - - 创建`rightProducts`数组,存储每个元素右侧所有元素的乘积 - -2. **计算左侧乘积**(从左到右遍历): - - 第一个元素左侧乘积初始化为1 - - 后续元素:`leftProducts[i] = nums[i-1] * leftProducts[i-1]` - -3. **计算右侧乘积**(从右到左遍历): - - 最后一个元素右侧乘积初始化为1 - - 前序元素:`rightProducts[i] = nums[i+1] * rightProducts[i+1]` - -4. **合并结果**: - - 遍历每个位置,将左右乘积相乘:`answer[i] = leftProducts[i] * rightProducts[i]` - -5. **返回结果数组** - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer[]} -def product_except_self(nums) - # nums: [1, 2, 3, 4] - # left_products: [1, 1, 2, 6] - # right_products: [24,12, 4, 1] - # answer: [24,12, 8, 6] - size = nums.size - - left_products = Array.new(size, 1) - (1...size).each do |i| - left_products[i] = nums[i - 1] * left_products[i - 1] - end - - right_products = Array.new(size, 1) - (size - 2).downto(0) do |i| - right_products[i] = nums[i + 1] * right_products[i + 1] - end - - answer = [] - (0...size).each do |i| - answer << left_products[i] * right_products[i] - end - - answer -end -``` - -## Python - -```python -class Solution: - def productExceptSelf(self, nums: List[int]) -> List[int]: - size = len(nums) - - # nums: [1, 2, 3, 4] - # left_products: [1, 1, 2, 6] - # right_products: [24,12, 4, 1] - # answer: [24,12, 8, 6] - left_products = [1] * size - for i in range(1, size): - left_products[i] = nums[i - 1] * left_products[i - 1] - - right_products = [1] * size - for i in range(size - 2, -1, -1): - right_products[i] = nums[i + 1] * right_products[i + 1] - - answer = [] - for i in range(size): - answer.append(left_products[i] * right_products[i]) - - return answer -``` - -## Java - -```java -class Solution { - public int[] productExceptSelf(int[] nums) { - int size = nums.length; - // nums: [1, 2, 3, 4] - // left_products: [1, 1, 2, 6] - // right_products: [24,12, 4, 1] - // answer: [24,12, 8, 6] - int[] leftProducts = new int[size]; - leftProducts[0] = 1; - for (int i = 1; i < size; i++) { - leftProducts[i] = nums[i - 1] * leftProducts[i - 1]; - } - - int[] rightProducts = new int[size]; - rightProducts[size - 1] = 1; - for (int i = size - 2; i >= 0; i--) { - rightProducts[i] = nums[i + 1] * rightProducts[i + 1]; - } - - int[] answer = new int[size]; - for (int i = 0; i < size; i++) { - answer[i] = leftProducts[i] * rightProducts[i]; - } - - return answer; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector productExceptSelf(vector& nums) { - int size = nums.size(); - // nums: [1, 2, 3, 4] - // left_products: [1, 1, 2, 6] - // right_products: [24,12, 4, 1] - // answer: [24,12, 8, 6] - vector left_products(size, 1); - for (int i = 1; i < size; i++) { - left_products[i] = nums[i - 1] * left_products[i - 1]; - } - - vector right_products(size, 1); - for (int i = size - 2; i >= 0; i--) { - right_products[i] = nums[i + 1] * right_products[i + 1]; - } - - vector answer(size); - for (int i = 0; i < size; i++) { - answer[i] = left_products[i] * right_products[i]; - } - - return answer; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number[]} - */ -var productExceptSelf = function(nums) { - const size = nums.length - - const leftProducts = new Array(size).fill(1) - for (let i = 1; i < size; i++) { - leftProducts[i] = nums[i - 1] * leftProducts[i - 1] - } - - const rightProducts = new Array(size).fill(1) - for (let i = size - 2; i >= 0; i--) { - rightProducts[i] = nums[i + 1] * rightProducts[i + 1] - } - - const answer = [] - for (let i = 0; i < size; i++) { - answer.push(leftProducts[i] * rightProducts[i]) - } - - return answer -}; - -``` - -## C# - -```csharp -public class Solution -{ - public int[] ProductExceptSelf(int[] nums) - { - int size = nums.Length; - // nums: [1, 2, 3, 4] - // left_products: [1, 1, 2, 6] - // right_products: [24,12, 4, 1] - // answer: [24,12, 8, 6] - int[] leftProducts = new int[size]; - leftProducts[0] = 1; - - for (int i = 1; i < size; i++) - leftProducts[i] = nums[i - 1] * leftProducts[i - 1]; - - int[] rightProducts = new int[size]; - rightProducts[size - 1] = 1; - - for (int i = size - 2; i >= 0; i--) - rightProducts[i] = nums[i + 1] * rightProducts[i + 1]; - - int[] answer = new int[size]; - - for (int i = 0; i < size; i++) - answer[i] = leftProducts[i] * rightProducts[i]; - - return answer; - } -} -``` - -## Go - -```go -func productExceptSelf(nums []int) []int { - size := len(nums) - - leftProducts := make([]int, size) - leftProducts[0] = 1 - for i := 1; i < size; i++ { - leftProducts[i] = nums[i - 1] * leftProducts[i - 1] - } - - rightProducts := make([]int, size) - rightProducts[size - 1] = 1 - for i := size - 2; i >= 0; i-- { - rightProducts[i] = nums[i + 1] * rightProducts[i + 1] - } - - answer := make([]int, size) - for i := 0; i < size; i++ { - answer[i] = leftProducts[i] * rightProducts[i] - } - - return answer -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -1. **空间优化**:利用输出数组存储中间结果,避免额外空间 -2. **两阶段计算**:先计算左侧乘积存入结果,再动态计算右侧乘积并直接合并 -3. **原地操作**:仅使用一个变量动态维护右侧乘积 - -## 步骤 - -1. **初始化结果数组**: - - 创建大小相同的`answer`数组,初始值全1 - -2. **计算左侧乘积**(左→右遍历): - - 初始化`left_product = 1` - - 遍历时:`answer[i] = left_product`,然后`left_product *= nums[i]` - -3. **计算右侧乘积并合并**(右→左遍历): - - 初始化`right_product = 1` - - 遍历时:`answer[i] *= right_product`,然后`right_product *= nums[i]` - -4. **返回结果数组** - - 空间复杂度:O(1)(输出数组不计入空间复杂度) - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer[]} -def product_except_self(nums) - size = nums.size - answer = Array.new(size, 1) - - left_product = 1 - (0...size).each do |i| - answer[i] = left_product - left_product *= nums[i] - end - - # nums: [1, 2, 3, 4] - # answer: [1, 1, 2, 6] left_product done - # answer: [24,12, 8, 6] right_product done - - right_product = 1 - (size - 1).downto(0) do |i| - answer[i] *= right_product - right_product *= nums[i] - end - - answer -end -``` - -## Python - -```python -class Solution: - def productExceptSelf(self, nums: List[int]) -> List[int]: - size = len(nums) - answer = [1] * size - - left_product = 1 - for i in range(size): - answer[i] = left_product - left_product *= nums[i] - - # nums: [1, 2, 3, 4] - # answer: [1, 1, 2, 6] left_product done - # answer: [24,12, 8, 6] right_product done - - right_product = 1 - for i in range(size-1, -1, -1): - answer[i] *= right_product - right_product *= nums[i] - - return answer -``` - -## Java - -```java -class Solution { - public int[] productExceptSelf(int[] nums) { - int size = nums.length; - int[] answer = new int[size]; - Arrays.fill(answer, 1); - - int leftProduct = 1; - for (int i = 0; i < size; i++) { - answer[i] = leftProduct; - leftProduct *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] leftProduct done - // answer: [24,12, 8, 6] rightProduct done - - int rightProduct = 1; - for (int i = size - 1; i >= 0; i--) { - answer[i] *= rightProduct; - rightProduct *= nums[i]; - } - - return answer; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector productExceptSelf(vector& nums) { - int size = nums.size(); - vector answer(size, 1); - - int left_product = 1; - for (int i = 0; i < size; ++i) { - answer[i] = left_product; - left_product *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] left_product done - // answer: [24,12, 8, 6] right_product done - - int right_product = 1; - for (int i = size - 1; i >= 0; --i) { - answer[i] *= right_product; - right_product *= nums[i]; - } - - return answer; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number[]} - */ -var productExceptSelf = function(nums) { - const answer = []; - let left_product = 1; - - for (let i = 0; i < nums.length; i++) { - answer[i] = left_product; - left_product *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] left_product done - // answer: [24,12, 8, 6] right_product done - - right_product = 1; - - for (let i = nums.length - 1; i >= 0; i--) { - answer[i] *= right_product; - right_product *= nums[i]; - } - - return answer; -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] ProductExceptSelf(int[] nums) - { - int size = nums.Length; - int[] answer = new int[size]; - Array.Fill(answer, 1); - - int leftProduct = 1; - for (int i = 0; i < size; i++) - { - answer[i] = leftProduct; - leftProduct *= nums[i]; - } - - // nums: [1, 2, 3, 4] - // answer: [1, 1, 2, 6] leftProduct done - // answer: [24,12, 8, 6] rightProduct done - - int rightProduct = 1; - for (int i = size - 1; i >= 0; i--) - { - answer[i] *= rightProduct; - rightProduct *= nums[i]; - } - - return answer; - } -} -``` - -## Go - -```go -func productExceptSelf(nums []int) []int { - n := len(nums) - answer := make([]int, n) - - answer[0] = 1 - for i := 1; i < n; i++ { - answer[i] = answer[i-1] * nums[i-1] - } - - right := 1 - for i := n - 1; i >= 0; i-- { - answer[i] *= right - right *= nums[i] - } - - return answer -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[238. 除自身以外数组的乘积 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/238-product-of-array-except-self). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/24-swap-nodes-in-pairs.md b/zh/1-1000/24-swap-nodes-in-pairs.md deleted file mode 100644 index fe64f5c..0000000 --- a/zh/1-1000/24-swap-nodes-in-pairs.md +++ /dev/null @@ -1,379 +0,0 @@ -# 24. 两两交换链表中的节点 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[24. 两两交换链表中的节点 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/24-swap-nodes-in-pairs),体验更佳! - -力扣链接:[24. 两两交换链表中的节点](https://leetcode.cn/problems/swap-nodes-in-pairs), 难度等级:**中等**。 - -## LeetCode “24. 两两交换链表中的节点”问题描述 - -给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 - -### [示例 1] - -![](../../images/examples/24_1.jpg) - -**输入**: `head = [1,2,3,4]` - -**输出**: `[2,1,4,3]` - -### [示例 2] - -**输入**: `head = []` - -**输出**: `[]` - -### [示例 3] - -**输入**: `head = [1]` - -**输出**: `[1]` - -### [示例 4] - -**输入**: `head = [1,2,3]` - -**输出**: `[2,1,3]` - -### [约束] - -- 链表中节点的数目在范围 `[0, 100]` 内 -- `0 <= Node.val <= 100` - -## 思路 - -在做本题前,建议先完成简单题目[206. Reverse Linked List](206-reverse-linked-list.md)。 - -1. 解决这个问题,依然至少需要定义两个变量:`current`和`previous`。 -2. 循环条件应是`while (current.next != null)`,而不应该是`while (current != null)`,因为需要操作`current.next.next`。 - -## 步骤 - -1. 遍历所有节点。 - - ```java - var previous = null; - var current = head; - - while (current != null) { - current = current.next; - } - ``` - -2. 因为每两个节点进行一次位置互换,所以需要改为一次走两步。 - - ```java - var previous = null; - var current = head; - - while (current != null && current.next != null) { // 1 - var nextNext = current.next.next; // 2 - current = nextNext; // 3 - } - ``` - -3. 交换 `current` 和 `current.next` 的位置。 - - ```java - var previous = null; - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - current.next.next = current; // 1 - current.next = nextNext; // 2 - - current = nextNext; - } - ``` - -4. 处理 `previous`。 - - ```java - var previous = null; - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - previous.next = current.next; // 1 - current.next.next = current; - current.next = nextNext; - - previous = current; // 2 - current = nextNext; - } - ``` - -5. 确定返回值。因为`head`节点在节点数量超过1时,会被交换到第二个节点的位置,为了统一方便处理,最好加入`dummy_head`节点。 - - ```java - var dummyHead = new ListNode(); // 1 - dummyHead.next = head; // 2 - - var previous = dummyHead; // 3 - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - previous.next = current.next; - current.next.next = current; - current.next = nextNext; - - previous = current; - current = nextNext; - } - - return dummyHead.next; // 4 - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -/** - * 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; } - * } - */ - -class Solution { - public ListNode swapPairs(ListNode head) { - var dummyHead = new ListNode(0, head); - var previous = dummyHead; - var current = head; - - while (current != null && current.next != null) { - var nextNext = current.next.next; - - previous.next = current.next; - current.next.next = current; - current.next = nextNext; - - previous = current; - current = nextNext; - } - - return dummyHead.next; - } -} -``` - -## Python - -```python -# class ListNode: -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next - -class Solution: - def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: - dummy_head = ListNode(next=head) - previous = dummy_head - current = head - - while current and current.next: - next_next = current.next.next - - previous.next = current.next - current.next.next = current - current.next = next_next - - previous = current - current = next_next - - return dummy_head.next -``` - -## C++ - -```cpp -/** - * struct ListNode { - * int val; - * ListNode *next; - * ListNode() : val(0), next(nullptr) {} - * ListNode(int x) : val(x), next(nullptr) {} - * ListNode(int x, ListNode *next) : val(x), next(next) {} - * }; - */ -class Solution { -public: - ListNode* swapPairs(ListNode* head) { - auto dummy_head = new ListNode(0, head); - auto previous = dummy_head; - auto current = head; - - while (current != nullptr && current->next != nullptr) { - auto next_next = current->next->next; - - previous->next = current->next; - current->next->next = current; - current->next = next_next; - - previous = current; - current = next_next; - } - - auto result = dummy_head->next; - delete dummy_head; - return result; - } -}; -``` - -## JavaScript - -```javascript -/** - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -var swapPairs = function (head) { - const dummyHead = new ListNode(0, head) - - let previous = dummyHead - let current = head - - while (current != null && current.next != null) { - const nextNext = current.next.next - - previous.next = current.next - current.next.next = current - current.next = nextNext - - previous = current - current = nextNext - } - - return dummyHead.next -}; -``` - -## C# - -```csharp -/** - * public class ListNode { - * public int val; - * public ListNode next; - * public ListNode(int val=0, ListNode next=null) { - * this.val = val; - * this.next = next; - * } - * } - */ -public class Solution -{ - public ListNode SwapPairs(ListNode head) - { - var dummyHead = new ListNode(0, head); - var previous = dummyHead; - var current = head; - - while (current != null && current.next != null) - { - var nextNext = current.next.next; - - previous.next = current.next; - current.next.next = current; - current.next = nextNext; - - previous = current; - current = nextNext; - } - - return dummyHead.next; - } -} -``` - -## Go - -```go -/** - * type ListNode struct { - * Val int - * Next *ListNode - * } - */ -func swapPairs(head *ListNode) *ListNode { - dummyHead := &ListNode{0, head} - - previous := dummyHead - current := head - - for current != nil && current.Next != nil { - nextNext := current.Next.Next - - previous.Next = current.Next - current.Next.Next = current - current.Next = nextNext - - previous = current - current = nextNext - } - - return dummyHead.Next -} -``` - -## Ruby - -```ruby -# class ListNode -# attr_accessor :val, :next -# -# def initialize(val = 0, _next = nil) -# @val = val -# @next = _next -# end -# end - -def swap_pairs(head) - dummy_head = ListNode.new - dummy_head.next = head - - previous = dummy_head - current = head - - while current && current.next - next_next = current.next.next - - previous.next = current.next - current.next.next = current - current.next = next_next - - previous = current - current = next_next - end - - dummy_head.next -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[24. 两两交换链表中的节点 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/24-swap-nodes-in-pairs). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/242-valid-anagram.md b/zh/1-1000/242-valid-anagram.md deleted file mode 100644 index 47dbf72..0000000 --- a/zh/1-1000/242-valid-anagram.md +++ /dev/null @@ -1,224 +0,0 @@ -# 242. 有效的字母异位词 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[242. 有效的字母异位词 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/242-valid-anagram),体验更佳! - -力扣链接:[242. 有效的字母异位词](https://leetcode.cn/problems/valid-anagram), 难度等级:**简单**。 - -## LeetCode “242. 有效的字母异位词”问题描述 - -给定两个字符串 `s` 和 `t` ,编写一个函数来判断 `t` 是否是 `s` 的 **字母异位词**。 - -> *字母异位词*是通过重新排列不同单词或短语的字母而形成的单词或短语,并使用所有原字母一次。 - -### [示例 1] - -**输入**: `s = "anagram", t = "nagaram"` - -**输出**: `true` - -### [示例 2] - -**输入**: `s = "rat", t = "car"` - -**输出**: `false` - -### [约束] - -- `1 <= s.length, t.length <= 5 * 10^4` -- `s` 和 `t` 仅包含小写字母 - -## 思路 - -1. 如果两个字符串长度不同,直接返回`false`。 -2. 用两个`Hash tables`分别存储对两个字符串的统计数据,`key`为字符,`value`为该字符出现次数。 -3. 比较这两个`Hash tables`,看它们是否相等。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public boolean isAnagram(String s, String t) { - if (s.length() != t.length()) { - return false; - } - - var sCharToCount = new HashMap(); - for (var character : s.toCharArray()) { - sCharToCount.put(character, sCharToCount.getOrDefault(character, 0) + 1); - } - - var tCharToCount = new HashMap(); - for (var character : t.toCharArray()) { - tCharToCount.put(character, tCharToCount.getOrDefault(character, 0) + 1); - } - - return sCharToCount.equals(tCharToCount); - } -} -``` - -## Python - -```python -# from collections import defaultdict - -class Solution: - def isAnagram(self, s: str, t: str) -> bool: - if len(s) != len(t): - return False - - s_char_to_count = defaultdict(int) - for char in s: - s_char_to_count[char] += 1 - - t_char_to_count = defaultdict(int) - for char in t: - t_char_to_count[char] += 1 - - return s_char_to_count == t_char_to_count -``` - -## JavaScript - -```javascript -var isAnagram = function (s, t) { - if (s.length != t.length) { - return false; - } - - const sCharToCount = new Map() - const tCharToCount = new Map() - - for (const char of s) { - sCharToCount.set(char, (sCharToCount.get(char) || 0) + 1) - } - - for (const char of t) { - tCharToCount.set(char, (tCharToCount.get(char) || 0) + 1) - } - - return _.isEqual(sCharToCount, tCharToCount) -}; -``` - -## C# - -```csharp -public class Solution -{ - public bool IsAnagram(string s, string t) - { - if (s.Length != t.Length) - return false; - - var sCharToCount = new Dictionary(); - var tCharToCount = new Dictionary(); - - foreach (char character in s) - sCharToCount[character] = sCharToCount.GetValueOrDefault(character, 0) + 1; - - foreach (char character in t) - tCharToCount[character] = tCharToCount.GetValueOrDefault(character, 0) + 1; - - foreach (var entry in sCharToCount) - { - if (entry.Value != tCharToCount.GetValueOrDefault(entry.Key)) - { - return false; - } - } - - return true; - } -} -``` - -## Go - -```go -import "reflect" - -func isAnagram(s string, t string) bool { - if len(s) != len(t) { - return false - } - - // Create frequency maps for both strings - sCharCount := make(map[rune]int) - for _, char := range s { - sCharCount[char]++ - } - - tCharCount := make(map[rune]int) - for _, char := range t { - tCharCount[char]++ - } - - return reflect.DeepEqual(sCharCount, tCharCount) -} -``` - -## Ruby - -```ruby -def is_anagram(s, t) - return false if s.length != t.length - - s_char_to_count = Hash.new(0) - t_char_to_count = Hash.new(0) - - s.each_char do |char| - s_char_to_count[char] += 1 - end - - t.each_char do |char| - t_char_to_count[char] += 1 - end - - s_char_to_count == t_char_to_count -end -``` - -## C++ - -```cpp -class Solution { -public: - bool isAnagram(string s, string t) { - if (s.length() != t.length()) { - return false; - } - - unordered_map s_char_to_count; - for (char character : s) { - s_char_to_count[character]++; - } - - unordered_map t_char_to_count; - for (char character : t) { - t_char_to_count[character]++; - } - - return s_char_to_count == t_char_to_count; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[242. 有效的字母异位词 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/242-valid-anagram). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/27-remove-element.md b/zh/1-1000/27-remove-element.md deleted file mode 100644 index 4f4bc03..0000000 --- a/zh/1-1000/27-remove-element.md +++ /dev/null @@ -1,437 +0,0 @@ -# 27. 移除元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[27. 移除元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/27-remove-element),体验更佳! - -力扣链接:[27. 移除元素](https://leetcode.cn/problems/remove-element), 难度等级:**简单**。 - -## LeetCode “27. 移除元素”问题描述 - -给你一个数组 `nums` 和一个值 `val`,你需要 [原地](https://en.wikipedia.org/wiki/In-place_algorithm) 移除所有数值等于 `val` 的元素。元素的顺序可能发生改变。然后返回 `nums` 中与 `val` 不同的元素的数量。 - -假设 `nums` 中不等于 `val` 的元素数量为 `k`,要通过此题,您需要执行以下操作: - -- 更改 `nums` 数组,使 `nums` 的前 `k` 个元素包含不等于 `val` 的元素。`nums` 的其余元素和 `nums` 的大小并不重要。 -- 返回 `k`。 - -### [示例 1] - -**输入**: `nums = [3,2,2,3], val = 3` - -**输出**: `2, nums = [2,2,_,_]` - -**解释**: - -

你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
-你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

- - -### [示例 2] - -**输入**: `nums = [0,1,2,2,3,0,4,2], val = 2` - -**输出**: `5, nums = [0,1,4,0,3,_,_,_]` - -**解释**: - -

你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
-注意这五个元素可以任意顺序返回。
-你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

- - -### [约束] - -- `0 <= nums.length <= 100` -- `0 <= nums[i] <= 50` -- `0 <= val <= 100` - -### [Hints] - -
- 提示 1 - The problem statement clearly asks us to modify the array in-place and it also says that the element beyond the new length of the array can be anything. Given an element, we need to remove all the occurrences of it from the array. We don't technically need to **remove** that element per-say, right? - - -
- -
- 提示 2 - We can move all the occurrences of this element to the end of the array. Use two pointers! - - ![](../../images/hints/27_2.png) -
- -
- 提示 3 - Yet another direction of thought is to consider the elements to be removed as non-existent. In a single pass, if we keep copying the visible elements in-place, that should also solve this problem for us. - - -
- -## 思路 1 - -- `双指针`,一左一右,左侧的指向数组头部,右侧的指向数组尾部。 -- 如果发现左侧指针对应的数值等于*val*,并且右侧指针对应的数值不等于*val*,就进行值交换。 -- 这种手段容易想到,但代码量比起`快慢指针`要多。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -class Solution { - public int removeElement(int[] nums, int val) { - var left = 0; - var right = nums.length - 1; - - while (left <= right) { - if (nums[left] != val) { - left += 1; - continue; - } - - if (nums[right] == val) { - right -= 1; - continue; - } - - nums[left] = nums[right]; - left += 1; - right -= 1; - } - - return left; - } -} -``` - -## Python - -```python -class Solution: - def removeElement(self, nums: List[int], val: int) -> int: - left = 0 - right = len(nums) - 1 - - while left <= right: - if nums[left] != val: - left += 1 - continue - - if nums[right] == val: - right -= 1 - continue - - nums[left] = nums[right] - left += 1 - right -= 1 - - return left -``` - -## C++ - -```cpp -class Solution { -public: - int removeElement(vector& nums, int val) { - int left = 0; - int right = nums.size() - 1; - - while (left <= right) { - if (nums[left] != val) { - left += 1; - continue; - } - - if (nums[right] == val) { - right -= 1; - continue; - } - - nums[left] = nums[right]; - left += 1; - right -= 1; - } - - return left; - } -}; -``` - -## JavaScript - -```javascript -var removeElement = function (nums, val) { - let left = 0 - let right = nums.length - 1 - - while (left <= right) { - if (nums[left] != val) { - left += 1 - continue - } - - if (nums[right] == val) { - right -= 1 - continue - } - - nums[left] = nums[right] - left += 1 - right -= 1 - } - - return left -}; -``` - -## C# - -```csharp -public class Solution -{ - public int RemoveElement(int[] nums, int val) - { - int left = 0; - int right = nums.Length - 1; - - while (left <= right) - { - if (nums[left] != val) - { - left += 1; - continue; - } - - if (nums[right] == val) - { - right -= 1; - continue; - } - - nums[left] = nums[right]; - left += 1; - right -= 1; - } - - return left; - } -} -``` - -## Go - -```go -func removeElement(nums []int, val int) int { - left := 0 - right := len(nums) - 1 - - for left <= right { - if nums[left] != val { - left += 1 - continue - } - - if nums[right] == val { - right -= 1 - continue - } - - nums[left] = nums[right] - left++ - right-- - } - - return left -} -``` - -## Ruby - -```ruby -def remove_element(nums, val) - left = 0 - right = nums.size - 1 - - while left <= right - if nums[left] != val - left += 1 - next - end - - if (nums[right] == val) - right -= 1 - next - end - - nums[left] = nums[right] - left += 1 - right -= 1 - end - - left -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -- `快慢指针方法`,指两个指针起初都指向数组头部,后来一个指针走得更快些。 -- 对于本题,什么情况下需要让快指针走快?就是快指针对应的值等于*val*时。而慢指针要保证走过的每个值都不等于*val*。 -- 值的交换就发生在快指针对应的值不等于*val*,慢指针对应的值等于*val*的时候。 -- 这种手段不容易想到,但比`左右双指针技术`更简洁。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -class Solution { - public int removeElement(int[] nums, int val) { - var slowIndex = 0; - - for (var num : nums) { // This line is the most important. You'd better memorize it. - if (num != val) { - nums[slowIndex] = num; - slowIndex += 1; - } - } - - return slowIndex; - } -} -``` - -## Python - -```python -class Solution: - def removeElement(self, nums: List[int], val: int) -> int: - slow_index = 0 - - for num in nums: # This line is the most important. You'd better memorize it. - if num != val: - nums[slow_index] = num - slow_index += 1 - - return slow_index -``` - -## C++ - -```cpp -class Solution { -public: - int removeElement(vector& nums, int val) { - auto slow_index = 0; - - for (auto num : nums) { // This line is the most important. You'd better memorize it. - if (num != val) { - nums[slow_index] = num; - slow_index += 1; - } - } - - return slow_index; - } -}; -``` - -## JavaScript - -```javascript -var removeElement = function (nums, val) { - let slowIndex = 0 - - nums.forEach((num) => { // This line is the most important. You'd better memorize it. - if (num != val) { - nums[slowIndex] = num - slowIndex += 1 - } - }) - - return slowIndex -}; -``` - -## C# - -```csharp -public class Solution -{ - public int RemoveElement(int[] nums, int val) - { - int slowIndex = 0; - - foreach (int num in nums) // This line is the most important. You'd better memorize it. - { - if (num != val) - { - nums[slowIndex] = num; - slowIndex += 1; - } - } - - return slowIndex; - } -} -``` - -## Go - -```go -func removeElement(nums []int, val int) int { - slowIndex := 0 - - for _, num := range nums { // This line is the most important. You'd better memorize it. - if num != val { - nums[slowIndex] = num - slowIndex += 1 - } - } - - return slowIndex -} -``` - -## Ruby - -```ruby -def remove_element(nums, val) - slow_index = 0 - - nums.each do |num| # This line is the most important. You'd better memorize it. - if num != val - nums[slow_index] = num - slow_index += 1 - end - end - - slow_index -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[27. 移除元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/27-remove-element). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/279-perfect-squares.md b/zh/1-1000/279-perfect-squares.md deleted file mode 100644 index d446efd..0000000 --- a/zh/1-1000/279-perfect-squares.md +++ /dev/null @@ -1,178 +0,0 @@ -# 279. Perfect Squares -LeetCode link: [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/) - -## LeetCode problem description -> Given an integer `n`, return the **least** number of perfect square numbers that sum to `n`. - -A **perfect square** is an integer that is the square of an integer; in other words, it is the product of some integer with itself. For example, `1`, `4`, `9`, and 16 are perfect squares while `3` and `11` are not. -``` -------------------------------------------------------------- -[Example 1] - -Input: n = 12 -Output: 3 -Explanation: 12 = 4 + 4 + 4. -------------------------------------------------------------- -[Example 2] - -Input: n = 13 -Output: 2 -Explanation: 13 = 4 + 9. -------------------------------------------------------------- -[Constraints] - -1 <= n <= 10000 -------------------------------------------------------------- -``` - -## Thoughts -It is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * Sqrt(n))`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int NumSquares(int n) - { - int defaultValue = n + 2; // As long as the value is greater than 'n', it doesn't matter how much it is. - int[] dp = Enumerable.Repeat(defaultValue, n + 1).ToArray(); - dp[0] = 0; - - for (var i = 1; i < dp.Length; i++) - { - for (var j = 1; j * j <= i; j++) - { - dp[i] = Math.Min(dp[i], dp[i - j * j] + 1); - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def numSquares(self, n: int) -> int: - default_value = n + 2 # As long as the value is greater than 'n', it doesn't matter how much it is. - dp = [default_value] * (n + 1) - dp[0] = 0 - - for i in range(1, len(dp)): - j = 1 - while i >= j * j: - dp[i] = min(dp[i], dp[i - j * j] + 1) - j += 1 - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int numSquares(int n) { - auto default_value = n + 2; // As long as the value is greater than 'n', it doesn't matter how much it is. - auto dp = vector(n + 1, default_value); - dp[0] = 0; - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j * j <= i; j++) { - dp[i] = min(dp[i], dp[i - j * j] + 1); - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int numSquares(int n) { - var defaultValue = n + 2; // As long as the value is greater than 'n', it doesn't matter how much it is. - var dp = new int[n + 1]; - Arrays.fill(dp, defaultValue); - dp[0] = 0; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j * j <= i; j++) { - dp[i] = Math.min(dp[i], dp[i - j * j] + 1); - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -```javascript -var numSquares = function (n) { - const DEFAULT_VALUE = n + 2 // As long as the value is greater than 'n', it doesn't matter how much it is. - const dp = Array(n + 1).fill(DEFAULT_VALUE) - dp[0] = 0 - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j * j <= i; j++) { - dp[i] = Math.min(dp[i], dp[i - j * j] + 1) - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func numSquares(n int) int { - defaultValue := n + 2 // As long as the value is greater than 'n', it doesn't matter how much it is. - dp := slices.Repeat([]int{defaultValue}, n + 1) - dp[0] = 0 - - for i := 1; i < len(dp); i++ { - for j := 1; j * j <= i; j++ { - dp[i] = min(dp[i], dp[i - j * j] + 1) - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def num_squares(n) - default_value = n + 2 # As long as the value is greater than 'n', it doesn't matter how much it is. - dp = Array.new(n + 1, default_value) - dp[0] = 0 - - (1...dp.size).each do |i| - j = 1 - while i >= j * j - dp[i] = [ dp[i], dp[i - j * j] + 1 ].min - j += 1 - end - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md b/zh/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md deleted file mode 100644 index e5a6720..0000000 --- a/zh/1-1000/28-find-the-index-of-the-first-occurrence-in-a-string.md +++ /dev/null @@ -1,204 +0,0 @@ -# 28. 找出字符串中第一个匹配项的下标 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[28. 找出字符串中第一个匹配项的下标 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/28-find-the-index-of-the-first-occurrence-in-a-string),体验更佳! - -力扣链接:[28. 找出字符串中第一个匹配项的下标](https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string), 难度等级:**简单**。 - -## LeetCode “28. 找出字符串中第一个匹配项的下标”问题描述 - -给你两个字符串 `haystack` 和 `needle` ,请你在 `haystack` 字符串中找出 `needle` 字符串的第一个匹配项的下标(下标从 `0` 开始)。如果 `needle` 不是 `haystack` 的一部分,则返回 `-1` 。 - -### [示例 1] - -**输入**: `haystack = "sadbutsad", needle = "sad"` - -**输出**: `0` - -**解释**: `"sad" 在下标 0 和 6 处匹配。 -第一个匹配项的下标是 0 ,所以返回 0 。` - -### [示例 2] - -**输入**: `haystack = "leetcode", needle = "leeto"` - -**输出**: `-1` - -**解释**: `"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。` - -### [约束] - -- `1 <= haystack.length, needle.length <= 10^4` -- `haystack` 和 `needle` 仅由小写英文字符组成 - -## 思路 - -- 这样的题目,如果用内置的`index()`,一行代码就可以实现。显然,出题人是想考察我们对循环的控制能力。 -- 针对 `heystack`,依次遍历每个字符。可能出现两种情况: - 1. 该字符与`needle`的首字母不相等。这时处理下一个字符。 - 2. 该字符与`needle`的首字母相等,则在一个内部循环中继续比较继续比较`heystack`和`needle`的下一个字符,直到不相等或者`needle`已经完全匹配。 - -- 本题直接看代码比较容易理解。 - -## 复杂度 - -- 时间复杂度: `O(N + M)`. -- 空间复杂度: `O(1)`. - -## Python - -```python -class Solution: - def strStr(self, haystack: str, needle: str) -> int: - for i in range(len(haystack)): - j = 0 - - while i + j < len(haystack) and haystack[i + j] == needle[j]: - j += 1 - - if j == len(needle): - return i - - return -1 -``` - -## JavaScript - -```javascript -var strStr = function (haystack, needle) { - for (let i = 0; i < haystack.length; i++) { - let j = 0 - - while (i + j < haystack.length && haystack[i + j] == needle[j]) { - j += 1 - - if (j == needle.length) { - return i - } - } - } - - return -1 -}; -``` - -## Ruby - -```ruby -# @param {String} haystack -# @param {String} needle -# @return {Integer} -def str_str(haystack, needle) - (0...haystack.length).each do |i| - j = 0 - - while i + j < haystack.length && haystack[i + j] == needle[j] - j += 1 - - return i if j == needle.length - end - end - - -1 -end -``` - -## C++ - -```cpp -class Solution { -public: - int strStr(string haystack, string needle) { - for (int i = 0; i < haystack.length(); i++) { - int j = 0; - - while (i + j < haystack.length() && haystack[i + j] == needle[j]) { - j++; - - if (j == needle.length()) { - return i; - } - } - } - - return -1; - } -}; -``` - -## Java - -```java -class Solution { - public int strStr(String haystack, String needle) { - for (int i = 0; i < haystack.length(); i++) { - int j = 0; - - while (i + j < haystack.length() && haystack.charAt(i + j) == needle.charAt(j)) { - j++; - - if (j == needle.length()) { - return i; - } - } - } - - return -1; - } -} -``` - -## Go - -```go -func strStr(haystack string, needle string) int { - for i := 0; i < len(haystack); i++ { - j := 0 - - for i+j < len(haystack) && haystack[i+j] == needle[j] { - j++ - - if j == len(needle) { - return i - } - } - } - - return -1 -} -``` - -## C# - -```csharp -public class Solution { - public int StrStr(string haystack, string needle) { - for (int i = 0; i < haystack.Length; i++) { - int j = 0; - - while (i + j < haystack.Length && haystack[i + j] == needle[j]) { - j++; - - if (j == needle.Length) { - return i; - } - } - } - - return -1; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[28. 找出字符串中第一个匹配项的下标 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/28-find-the-index-of-the-first-occurrence-in-a-string). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/300-longest-increasing-subsequence.md b/zh/1-1000/300-longest-increasing-subsequence.md deleted file mode 100644 index b5ca3bf..0000000 --- a/zh/1-1000/300-longest-increasing-subsequence.md +++ /dev/null @@ -1,143 +0,0 @@ -# 300. Longest Increasing Subsequence -LeetCode link: [300. Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) - -## LeetCode problem description -Given an integer array `nums`, return the length of the **longest strictly increasing subsequence**. - -``` -------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [10,9,2,5,3,7,101,18] -Output: 4 - -Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. -------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [0,1,0,3,2,3] -Output: 4 -------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums = [7,7,7,7,7,7,7] -Output: 1 -------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 2500 --10000 <= nums[i] <= 10000 -------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 4 to 7 languages are given. - -### Complexity -* Time: `O(n * n)`. -* Space: `O(n)`. - -## C# -```c# -// 10, 9, 2, 5, 3, 7, 4, 3,101,18 # nums -// 1, 1, 1, 2, 2, 3, 3, 2, 4,4 # dp -public class Solution -{ - public int LengthOfLIS(int[] nums) - { - var dp = new int[nums.Length]; - Array.Fill(dp, 1); - - for (var i = 1; i < nums.Length; i++) - { - for (var j = i - 1; j >= 0; j--) - { - if (nums[i] > nums[j]) - { - dp[i] = Math.Max(dp[i], dp[j] + 1); - } - } - } - - return dp.Max(); - } -} -``` - -## Python -```python -class Solution: - def lengthOfLIS(self, nums: List[int]) -> int: - dp = [1] * len(nums) - - for i in range(1, len(dp)): - for j in range(i - 1, -1, -1): - if nums[i] > nums[j] and dp[j] + 1 > dp[i]: - dp[i] = dp[j] + 1 - - return max(dp) -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -class Solution { - public int lengthOfLIS(int[] nums) { - var dp = new int[nums.length]; - Arrays.fill(dp, 1); - - for (var i = 1; i < nums.length; i++) { - for (var j = i - 1; j >= 0; j--) { - if (nums[i] > nums[j]) { - dp[i] = Math.max(dp[i], dp[j] + 1); - } - } - } - - return IntStream.of(dp).max().getAsInt(); - } -} -``` - -## JavaScript -```javascript -var lengthOfLIS = function (nums) { - const dp = Array(nums.length).fill(1) - - nums.forEach((num, i) => { - for (let j = i - 1; j >= 0; j--) { - if (num > nums[j]) { - dp[i] = Math.max(dp[i], dp[j] + 1) - } - } - }) - - return Math.max(...dp) -}; -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/303-range-sum-query-immutable.md b/zh/1-1000/303-range-sum-query-immutable.md deleted file mode 100644 index 78aadb7..0000000 --- a/zh/1-1000/303-range-sum-query-immutable.md +++ /dev/null @@ -1,240 +0,0 @@ -# 303. 区域和检索 - 数组不可变 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[303. 区域和检索 - 数组不可变 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/303-range-sum-query-immutable),体验更佳! - -力扣链接:[303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable), 难度等级:**简单**。 - -## LeetCode “303. 区域和检索 - 数组不可变”问题描述 - -给定一个整数数组 `nums`,处理以下类型的多个查询: - -计算索引 `left` 和 `right` (包含 `left` 和 `right`)之间的 `nums` 元素的 **和** ,其中 `left <= right` -实现 `NumArray` 类: - -- `NumArray(int[] nums)` 使用数组 `nums` 初始化对象 -- `int sumRange(int i, int j)` 返回数组 `nums` 中索引 `left` 和 `right` 之间的元素的 **总和** ,包含 `left` 和 `right` 两点(也就是 `nums[left] + nums[left + 1] + ... + nums[right]` ) - -### [示例 1] - -**输入**: `["NumArray", "sumRange", "sumRange", "sumRange"] [[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]` - -**输出**: `[null, 1, -1, -3]` - -**解释**: - -

NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
-numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
-numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
-numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3

- - -### [约束] - -- `1 <= nums.length <= 10^4` -- `-10^5 <= nums[i] <= 10^5` -- `0 <= left <= right < nums.length` -- 最多调用 `10^4` 次 `sumRange` 方法 - -## 思路 1 - -- 使用新数组 `prefix_sums` 保存前面元素的总和。 -- `prefix_sums` 的第一个元素为 `0`,因为前缀和 **不包含当前元素**。 -- 要查找从索引 `left` 到 `right`(含)元素的总和,只需使用 `prefix_sums[right + 1] - prefix_sums[left]`。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class NumArray { - private int[] prefixSums; - - public NumArray(int[] nums) { - prefixSums = new int[nums.length + 1]; - var sum = 0; - - for (var i = 0; i < nums.length; i++) { - sum += nums[i]; - prefixSums[i + 1] = sum; - } - } - - public int sumRange(int left, int right) { - return prefixSums[right + 1] - prefixSums[left]; - } -} -``` - -## Python - -```python -class NumArray: - def __init__(self, nums: List[int]): - self.prefix_sums = [0] - sum_ = 0 - - for num in nums: - sum_ += num - self.prefix_sums.append(sum_) - - def sumRange(self, left: int, right: int) -> int: - return self.prefix_sums[right + 1] - self.prefix_sums[left] -``` - -## C++ - -```cpp -class NumArray { -private: - vector prefixSums; - -public: - NumArray(vector& nums) { - prefixSums.push_back(0); - auto sum = 0; - - for (auto num : nums) { - sum += num; - prefixSums.push_back(sum); - } - } - - int sumRange(int left, int right) { - return prefixSums[right + 1] - prefixSums[left]; - } -}; -``` - -## JavaScript - -```javascript -let prefixSums - -var NumArray = function (nums) { - prefixSums = [0] - let sum = 0 - - nums.forEach((num) => { - sum += num - prefixSums.push(sum) - }) -}; - -NumArray.prototype.sumRange = function (left, right) { - return prefixSums[right + 1] - prefixSums[left] -}; -``` - -## C# - -```csharp -public class NumArray -{ - int[] prefixSums; - - public NumArray(int[] nums) - { - prefixSums = new int[nums.Length + 1]; - int sum = 0; - - for (int i = 0; i < nums.Length; i++) - { - sum += nums[i]; - prefixSums[i + 1] = sum; - } - } - - public int SumRange(int left, int right) - { - return prefixSums[right + 1] - prefixSums[left]; - } -} -``` - -## Go - -```go -type NumArray struct { - prefixSums []int -} - -func Constructor(nums []int) NumArray { - prefixSums := make([]int, len(nums) + 1) - sum := 0 - - for i, num := range nums { - sum += num - prefixSums[i + 1] = sum - } - - return NumArray{prefixSums} -} - -func (this *NumArray) SumRange(left int, right int) int { - return this.prefixSums[right + 1] - this.prefixSums[left] -} -``` - -## Ruby - -```ruby -class NumArray - def initialize(nums) - @prefix_sums = [0] - sum = 0 - - nums.each do |num| - sum += num - @prefix_sums << sum - end - end - - def sum_range(left, right) - @prefix_sums[right + 1] - @prefix_sums[left] - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -直接返回数组区域内值之和,虽然可以通过测试,但是如果测试用例更严格的话就会失败。 -所以我们还需要学习一种更有效的解决方案:`前缀和`方案。 - -## 复杂度 - -- 时间复杂度: `O(M * N)`. -- 空间复杂度: `O(M * N)`. - -## Python - -```python -class NumArray: - def __init__(self, nums: List[int]): - self.nums = nums - - def sumRange(self, left: int, right: int) -> int: - return sum(self.nums[left:right + 1]) -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[303. 区域和检索 - 数组不可变 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/303-range-sum-query-immutable). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md b/zh/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md deleted file mode 100644 index 547f3da..0000000 --- a/zh/1-1000/309-best-time-to-buy-and-sell-stock-with-cooldown.md +++ /dev/null @@ -1,140 +0,0 @@ -# 309. Best Time to Buy and Sell Stock with Cooldown -LeetCode link: [309. Best Time to Buy and Sell Stock with Cooldown](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day. - -Find the **maximum profit** you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions: - -* After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day). - -**Note**: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). - -``` -------------------------------------------------------------------------- -[Example 1] - -Input: prices = [1,2,3,0,2] -Output: 3 - -Explanation: transactions = [buy, sell, cooldown, buy, sell] -------------------------------------------------------------------------- -[Example 2] - -Input: prices = [1] -Output: 0 -------------------------------------------------------------------------- -[Constraints] - -1 <= prices.length <= 5000 -0 <= prices[i] <= 1000 -------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int]) -> int: - # 2 states: - # 0: hold stock - # 1) keep holding (last day is not a cooldown day) - # 2) today just bought (last day is a cooldown day) - # 1: no stock - # 1) keep no stock (today is not a cooldown day) - # 2) keep no stock (today is a cooldown day) - # 3) today just sold - # - # To make things clear, we have to go with 3 states. - # The process from 2 states to 3 states really makes things easier to understand! - # 3 states: - # 0: hold stock - # 1) keep holding (last day is not a cooldown day) - # 2) today just bought (last day is a cooldown day) - # 1: no stock (today is not a cooldown day) - # 1) keep no stock - # 2) today just sold - # 2: no stock (today is a cooldown day) - dp = [-prices[0], 0, 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], dc[2] - price) - dp[1] = max(dc[1], dc[0] + price) - dp[2] = dc[1] - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function(prices) { - const dp = [-prices[0], 0, 0] - - for (const price of prices.slice(1,)) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], dc[2] - price) - dp[1] = Math.max(dc[1], dc[0] + price) - dp[2] = dc[1] - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int) int { - dp := []int{-prices[0], 0, 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], dc[2] - prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i]) - dp[2] = dc[1] - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/322-coin-change.md b/zh/1-1000/322-coin-change.md deleted file mode 100644 index fbca4eb..0000000 --- a/zh/1-1000/322-coin-change.md +++ /dev/null @@ -1,214 +0,0 @@ -# 322. Coin Change -LeetCode link: [322. Coin Change](https://leetcode.com/problems/coin-change/) - -## LeetCode problem description -> You are given an integer array `coins` representing coins of different denominations and an integer `amount` representing a total amount of money. - -Return the **fewest number** of coins that you need to make up that `amount`. If that amount of money cannot be made up by any combination of the coins, return `-1`. - -You may assume that you have an **infinite** number of each kind of coin. - -``` -Example 1: - -Input: coins = [1,2,5], amount = 11 -Output: 3 - -Explanation: 11 = 5 + 5 + 1 ------------------------------------------------------------------------- - -Example 2: - -Input: coins = [2], amount = 3 -Output: -1 ------------------------------------------------------------------------- - -Constraints: - -1 <= coins.length <= 12 -1 <= coins[i] <= 2**31 - 1 -0 <= amount <= 10000 -``` - -## Thoughts -It is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int CoinChange(int[] coins, int amount) - { - int defaultValue = amount + 2; // As long as the value is greater than 'amount', it doesn't matter how much it is. - int[] dp = Enumerable.Repeat(defaultValue, amount + 1).ToArray(); - dp[0] = 0; - - for (var i = 1; i < dp.Length; i++) - { - foreach (int coin in coins) - { - if (i >= coin) - { - dp[i] = Math.Min(dp[i], dp[i - coin] + 1); - } - } - } - - if (dp.Last() == defaultValue) - return -1; - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def coinChange(self, coins: List[int], amount: int) -> int: - default_value = amount + 2 # As long as the value is greater than 'amount', it doesn't matter how much it is. - dp = [default_value] * (amount + 1) - dp[0] = 0 - - for i in range(1, len(dp)): - for coin in coins: - if i >= coin: - dp[i] = min(dp[i], dp[i - coin] + 1) - - if dp[-1] == default_value: - return -1 - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int coinChange(vector& coins, int amount) { - auto default_value = amount + 2; // As long as the value is greater than 'amount', it doesn't matter how much it is. - auto dp = vector(amount + 1, default_value); - dp[0] = 0; - - for (auto i = 1; i < dp.size(); i++) { - for (auto coin : coins) { - if (i >= coin) { - dp[i] = min(dp[i], dp[i - coin] + 1); - } - } - } - - if (dp.back() == default_value) { - return -1; - } - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int coinChange(int[] coins, int amount) { - var defaultValue = amount + 2; // As long as the value is greater than 'amount', it doesn't matter how much it is. - - var dp = new int[amount + 1]; - Arrays.fill(dp, defaultValue); - dp[0] = 0; - - for (var i = 1; i < dp.length; i++) { - for (var coin : coins) { - if (i >= coin) { - dp[i] = Math.min(dp[i], dp[i - coin] + 1); - } - } - } - - var result = dp[dp.length - 1]; - if (result == defaultValue) { - return -1; - } - return result; - } -} -``` - -## JavaScript -```javascript -var coinChange = function (coins, amount) { - const DEFAULT_VALUE = amount + 2 // As long as the value is greater than 'amount', it doesn't matter how much it is. - const dp = Array(amount + 1).fill(DEFAULT_VALUE) - dp[0] = 0 - - for (let i = 1; i < dp.length; i++) { - for (const coin of coins) { - if (i >= coin) { - dp[i] = Math.min(dp[i], dp[i - coin] + 1) - } - } - } - - if (dp.at(-1) == DEFAULT_VALUE) { - return -1 - } - return dp.at(-1) -}; -``` - -## Go -```go -func coinChange(coins []int, amount int) int { - defaultValue := amount + 2 // As long as the value is greater than 'amount', it doesn't matter how much it is. - dp := slices.Repeat([]int{defaultValue}, amount + 1) - dp[0] = 0 - - for i := 1; i < len(dp); i++ { - for _, coin := range coins { - if i >= coin { - dp[i] = min(dp[i], dp[i - coin] + 1) - } - } - } - - result := dp[len(dp) - 1] - if result == defaultValue { - return -1 - } - return result -} -``` - -## Ruby -```ruby -def coin_change(coins, amount) - default_value = amount + 2 # As long as the value is greater than 'amount', it doesn't matter how much it is. - dp = Array.new(amount + 1, default_value) - dp[0] = 0 - - (1...dp.size).each do |i| - coins.each do |coin| - dp[i] = [ dp[i], dp[i - coin] + 1 ].min if i >= coin - end - end - - return -1 if dp[-1] == default_value - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/337-house-robber-iii.md b/zh/1-1000/337-house-robber-iii.md deleted file mode 100644 index babfdc0..0000000 --- a/zh/1-1000/337-house-robber-iii.md +++ /dev/null @@ -1,268 +0,0 @@ -# 337. House Robber III -LeetCode link: [337. House Robber III](https://leetcode.com/problems/house-robber-iii/) - -## LeetCode problem description -The thief has found himself a new place for his thievery again. There is only one entrance to this area, called `root`. - -Besides the `root`, each house has one and only one parent house. After a tour, the smart thief realized that all houses in this place form a binary tree. **It will automatically contact the police if two directly-linked houses were broken into on the same night**. - -Given the `root` of the binary tree, return the **maximum amount of money** the thief can rob **without alerting the police**. -``` ------------------------------------------------------------------------- -[Example 1] - -Input: root = [3,2,3,null,3,null,1] -Output: 7 -Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7. ------------------------------------------------------------------------- -[Example 2] - -Input: root = [3,4,5,1,3,null,1] -Output: 9 -Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9. ------------------------------------------------------------------------- -[Constraints] - -The number of nodes in the tree is in the range [1, 10000]. -0 <= Node.val <= 10000 ------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3-7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Solution 1: Easier to understand -```python -class Solution: - def __init__(self): - self.node_to_money = defaultdict(int) - - # Uncomment the next line, you can solve it without using `self.node_to_money` dict. - # @cache - def rob(self, node: Optional[TreeNode]) -> int: - if node is None: - return 0 - - if node in self.node_to_money: - return self.node_to_money[node] - - money_exclude_node = self.rob(node.left) + self.rob(node.right) - - money_include_node = node.val - if node.left: - money_include_node += self.rob(node.left.left) + self.rob(node.left.right) - if node.right: - money_include_node += self.rob(node.right.left) + self.rob(node.right.right) - - self.node_to_money[node] = max(money_exclude_node, money_include_node) - - return self.node_to_money[node] -``` - -### Solution 2: Most concise -```python -class Solution: - def rob(self, root: Optional[TreeNode]) -> int: - return max(self.rob_tree(root)) - - def rob_tree(self, node): - if node is None: - return 0, 0 - - left_pair = self.rob_tree(node.left) - right_pair = self.rob_tree(node.right) - - return max(left_pair) + max(right_pair), node.val + left_pair[0] + right_pair[0] -``` - -### Solution 3: -```python -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, val=0, left=None, right=None): -# self.val = val -# self.left = left -# self.right = right - -class Solution: - def rob(self, root: Optional[TreeNode]) -> int: - return self.robbing(root)[0] - - def robbing(self, node): - if not node: - return 0, 0 - - left = self.robbing(node.left) - - right = self.robbing(node.right) - - return max(node.val + left[1] + right[1], left[0] + right[0]), left[0] + right[0] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -### Solution 1: Easier to understand -```javascript -const nodeToMoney = new Map() - -var rob = function (root) { - nodeToMoney.clear() - - return robTree(root) -}; - - -function robTree(node) { - if (node == null) { - return 0 - } - - if (nodeToMoney.has(node)) { - return nodeToMoney.get(node) - } - - const moneyExcludeNode = robTree(node.left) + robTree(node.right) - - let moneyIncludeNode = node.val - if (node.left) { - moneyIncludeNode += robTree(node.left.left) + robTree(node.left.right) - } - if (node.right) { - moneyIncludeNode += robTree(node.right.left) + robTree(node.right.right) - } - - nodeToMoney.set(node, Math.max(moneyExcludeNode, moneyIncludeNode)) - - return nodeToMoney.get(node) -} -``` - -### Solution 2: Most concise -```javascript -var rob = function (root) { - return Math.max(...robTree(root)) -}; - -function robTree(node) { - if (node == null) { - return [0, 0] - } - - const leftPair = robTree(node.left) - const rightPair = robTree(node.right) - - return [ - Math.max(...leftPair) + Math.max(...rightPair), - node.val + leftPair[0] + rightPair[0] - ] -} -``` - -## Go -### Solution 1: Easier to understand -```go -/** - * Definition for a binary tree node. - * type TreeNode struct { - * Val int - * Left *TreeNode - * Right *TreeNode - * } - */ -func rob(root *TreeNode) int { - nodeToMoney := map[*TreeNode]int{} - - var robTree func (*TreeNode) int - - robTree = func (node *TreeNode) int { - if node == nil { - return 0 - } - - if money, ok := nodeToMoney[node]; ok { - return money - } - - moneyExcludeNode := robTree(node.Left) + robTree(node.Right) - - moneyIncludeNode := node.Val - if node.Left != nil { - moneyIncludeNode += robTree(node.Left.Left) + robTree(node.Left.Right) - } - if node.Right != nil { - moneyIncludeNode += robTree(node.Right.Left) + robTree(node.Right.Right) - } - - nodeToMoney[node] = max(moneyExcludeNode, moneyIncludeNode) - - return nodeToMoney[node] - } - - return robTree(root) -} -``` - -### Solution 2: Most concise -```go -/** - * Definition for a binary tree node. - * type TreeNode struct { - * Val int - * Left *TreeNode - * Right *TreeNode - * } - */ -func rob(root *TreeNode) int { - return slices.Max(robTree(root)) -} - -func robTree(node *TreeNode) []int { - if node == nil { - return []int{0, 0} - } - - leftPair := robTree(node.Left) - rightPair := robTree(node.Right) - - return []int{ - slices.Max(leftPair) + slices.Max(rightPair), - node.Val + leftPair[0] + rightPair[0], - } -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/344-reverse-string.md b/zh/1-1000/344-reverse-string.md deleted file mode 100644 index 64b18ca..0000000 --- a/zh/1-1000/344-reverse-string.md +++ /dev/null @@ -1,221 +0,0 @@ -# 344. 反转字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[344. 反转字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/344-reverse-string),体验更佳! - -力扣链接:[344. 反转字符串](https://leetcode.cn/problems/reverse-string), 难度等级:**简单**。 - -## LeetCode “344. 反转字符串”问题描述 - -编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 `s` 的形式给出。 - -不要给另外的数组分配额外的空间,你必须 [原地](https://en.wikipedia.org/wiki/In-place_algorithm) **修改输入数组**、使用 `O(1)` 的额外空间解决这一问题。 - -### [示例 1] - -**输入**: `s = ["h","e","l","l","o"]` - -**输出**: `["o","l","l","e","h"]` - -### [示例 2] - -**输入**: `s = ["H","a","n","n","a","h"]` - -**输出**: `["h","a","n","n","a","H"]` - -### [约束] - -- `1 <= s.length <= 10^5` -- `s[i]` 都是 ASCII 码表中的可打印字符 - -### [Hints] - -
- 提示 1 - The entire logic for reversing a string is based on using the opposite directional two-pointer approach! - - -
- -## 思路 - -1. 这种问题用编程语言内置的`sort()`方法可以一行代码解决。如果面试中出这种题目,出题人考察的应该是不用内置方法如何做。 -2. 用**方向相对**的两个指针,最初时一个指针指向下标`0`,另一个指针指向下标`s.length - 1`。 -3. 遍历数组元素,循环条件为`while (left < right)`。在循环体内,`left += 1`, `right -= 1`。 -4. 在循环体内,交换数组中两个下标对应的值。 -5. 以上为`方向相对`的**双指针**的模板。 - -## 步骤 - -1. 用**方向相对的两个指针**,最初时一个指针指向下标`0`,另一个指针指向下标`s.length - 1`。 - - ```ruby - left = 0 - right = s.length - 1 - ``` - -2. 遍历数组元素,循环条件为`while (left < right)`。在循环体内,`left += 1`, `right -= 1`。 - - ```ruby - left = 0 - right = s.length - 1 - - while left < right # 1 - left += 1 # 2 - right -= 1 # 3 - end - ``` - -3. 在循环体内,交换数组中两个下标对应的值。 - - ```ruby - left = 0 - right = s.length - 1 - - while left < right - s[left], s[right] = s[right], s[left] # 1 - - left += 1 - right -= 1 - end - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -class Solution { - public void reverseString(char[] s) { - var left = 0; - var right = s.length - 1; - - while (left < right) { - var leftValue = s[left]; - s[left] = s[right]; - s[right] = leftValue; - - left++; - right--; - } - } -} -``` - -## Python - -```python -class Solution: - def reverseString(self, s: List[str]) -> None: - left = 0 - right = len(s) - 1 - - while left < right: - s[left], s[right] = s[right], s[left] - left += 1 - right -= 1 -``` - -## C++ - -```cpp -class Solution { -public: - void reverseString(vector& s) { - auto left = 0; - auto right = s.size() - 1; - - while (left < right) { - swap(s[left], s[right]); - - left++; - right--; - } - } -}; -``` - -## JavaScript - -```javascript -var reverseString = function (s) { - let left = 0 - let right = s.length - 1 - - while (left < right) { - [s[left], s[right]] = [s[right], s[left]] - - left++ - right-- - } -}; -``` - -## C# - -```csharp -public class Solution -{ - public void ReverseString(char[] s) - { - int left = 0; - int right = s.Length - 1; - - while (left < right) - { - (s[left], s[right]) = (s[right], s[left]); - - left++; - right--; - } - } -} -``` - -## Go - -```go -func reverseString(s []byte) { - left := 0 - right := len(s) - 1 - - for left < right { - s[left], s[right] = s[right], s[left] - - left++ - right-- - } -} -``` - -## Ruby - -```ruby -def reverse_string(s) - left = 0 - right = s.size - 1 - - while left < right - s[left], s[right] = s[right], s[left] - - left += 1 - right -= 1 - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[344. 反转字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/344-reverse-string). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/345-reverse-vowels-of-a-string.md b/zh/1-1000/345-reverse-vowels-of-a-string.md deleted file mode 100644 index 0bb139d..0000000 --- a/zh/1-1000/345-reverse-vowels-of-a-string.md +++ /dev/null @@ -1,303 +0,0 @@ -# 345. 反转字符串中的元音字母 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[345. 反转字符串中的元音字母 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/345-reverse-vowels-of-a-string),体验更佳! - -力扣链接:[345. 反转字符串中的元音字母](https://leetcode.cn/problems/reverse-vowels-of-a-string), 难度等级:**简单**。 - -## LeetCode “345. 反转字符串中的元音字母”问题描述 - -给你一个字符串 `s` ,仅反转字符串中的所有元音字母,并返回结果字符串。 - -元音字母包括 `'a'`, `'e'`, `'i'`, `'o'`, `'u'`,且可能以大小写两种形式出现不止一次。 - -### [示例 1] - -**输入**: `s = "IceCreAm"` - -**输出**: `"AceCreIm"` - -**解释**: - -

s 中的元音是 ['I', 'e', 'e', 'A']。反转这些元音,s 变为 "AceCreIm".

- - -### [示例 2] - -**输入**: `"leetcode"` - -**输出**: `"leotcede"` - -### [约束] - -- `1 <= s.length <= 3 * 10^5` -- `s` 由 **可打印的 ASCII** 字符组成 - -## 思路 - -双指针交换字符串中的元音字母。左指针从左找元音,右指针从右找元音,找到后交换,直到指针相遇。 - -## “左右双指针”的模式 - -代码框架如下: - -```java -int r = target.length() - 1; - -for (int l = 0; l < target.length(); l++) { // Important - // ... - if (l >= r) { - break; - } - - // ... - r--; -} -``` - -## 步骤 - -1. 初始化元音集合 -2. 某些语言,需要将字符串转字符数组(因字符串不可变) -3. 左指针`l`从`0`开始,右指针`r`从末尾开始 -4. 循环处理: - - `l`右移直到找到元音 - - `r`左移直到找到元音 - - 当`l < r`时交换这两个元音 -5. 返回处理后的字符串 - -## 复杂度 - -> 如果转换为字符数组,空间复杂度为 O(N)。 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1) or O(N)`. - -## Python - -```python -class Solution: - def reverseVowels(self, s: str) -> str: - vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'] - s = list(s) - r = len(s) - 1 - - for l in range(len(s)): # Important - if s[l] not in vowels: - continue - - while r > 0 and s[r] not in vowels: - r -= 1 - - if l >= r: - break - - s[l], s[r] = s[r], s[l] - r -= 1 - - return ''.join(s) -``` - -## Java - -```java -class Solution { - public String reverseVowels(String s) { - var vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); - var chars = s.toCharArray(); - int r = chars.length - 1; - - for (int l = 0; l < chars.length; l++) { // important - if (!vowels.contains(chars[l])) { - continue; - } - - while (r > 0 && !vowels.contains(chars[r])) { - r--; - } - - if (l >= r) { - break; - } - - // Swap the vowels - char temp = chars[l]; - chars[l] = chars[r]; - chars[r] = temp; - r--; - } - - return new String(chars); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string reverseVowels(string s) { - unordered_set vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'}; - int r = s.size() - 1; - - for (int l = 0; l < s.size(); l++) { // important - if (!vowels.contains(s[l])) { - continue; - } - - while (r > 0 && !vowels.contains(s[r])) { - r--; - } - - if (l >= r) { - break; - } - - swap(s[l], s[r]); - r--; - } - - return s; - } -}; -``` - -## JavaScript - -```javascript -var reverseVowels = function (s) { - const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) - const chars = s.split('') - let r = chars.length - 1 - - for (let l = 0; l < chars.length; l++) { // important - if (!vowels.has(chars[l])) { - continue - } - - while (r > 0 && !vowels.has(chars[r])) { - r-- - } - - if (l >= r) { - break - } - - [chars[l], chars[r]] = [chars[r], chars[l]] - r-- - } - - return chars.join('') -}; -``` - -## Ruby - -```ruby -def reverse_vowels(s) - vowels = Set.new(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) - r = s.size - 1 - - (0...s.size).each do |l| - unless vowels.include?(s[l]) - next - end - - while r > 0 && !vowels.include?(s[r]) - r -= 1 - end - - if l >= r - break - end - - s[l], s[r] = s[r], s[l] - r -= 1 - end - - s -end -``` - -## C# - -```csharp -public class Solution -{ - public string ReverseVowels(string s) - { - var vowels = new HashSet {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'}; - var chars = s.ToCharArray(); - int r = chars.Length - 1; - // important - for (int l = 0; l < chars.Length; l++) - { - if (!vowels.Contains(chars[l])) - { - continue; - } - - while (r > 0 && !vowels.Contains(chars[r])) - { - r--; - } - - if (l >= r) - { - break; - } - - (chars[l], chars[r]) = (chars[r], chars[l]); - r--; - } - - return new string(chars); - } -} -``` - -## Go - -```go -func reverseVowels(s string) string { - vowels := map[byte]bool{ - 'a': true, 'e': true, 'i': true, 'o': true, 'u': true, - 'A': true, 'E': true, 'I': true, 'O': true, 'U': true, - } - chars := []byte(s) - r := len(chars) - 1 - - for l := 0; l < len(chars); l++ { // important - if !vowels[chars[l]] { - continue - } - - for r > 0 && !vowels[chars[r]] { - r-- - } - - if l >= r { - break - } - - chars[l], chars[r] = chars[r], chars[l] - r-- - } - - return string(chars) -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[345. 反转字符串中的元音字母 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/345-reverse-vowels-of-a-string). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/349-intersection-of-two-arrays.md b/zh/1-1000/349-intersection-of-two-arrays.md deleted file mode 100644 index d10ffb9..0000000 --- a/zh/1-1000/349-intersection-of-two-arrays.md +++ /dev/null @@ -1,194 +0,0 @@ -# 349. 两个数组的交集 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[349. 两个数组的交集 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/349-intersection-of-two-arrays),体验更佳! - -力扣链接:[349. 两个数组的交集](https://leetcode.cn/problems/intersection-of-two-arrays), 难度等级:**简单**。 - -## LeetCode “349. 两个数组的交集”问题描述 - -给定两个数组 `nums1` 和 `nums2` ,返回 _它们的 **交集**_ 。输出结果中的每个元素一定是 **唯一** 的。我们可以 **不考虑输出结果的顺序**。 - -> 数组的交集: The intersection of two arrays is defined as the set of elements that are present in both arrays. - -### [示例 1] - -**输入**: `nums1 = [1,2,2,1], nums2 = [2,2]` - -**输出**: `[2]` - -### [示例 2] - -**输入**: `nums1 = [4,9,5], nums2 = [9,4,9,8,4]` - -**输出**: `[9,4]` - -**解释**: `[4,9] 也是可通过的` - -### [约束] - -- `1 <= nums1.length, nums2.length <= 1000` -- `0 <= nums1[i], nums2[i] <= 1000` - -## 思路 - -1. 把其中一个数组转为`set`,数据结构`set`的特点是元素不重复。 -2. 遍历另一个数组时,如果发现当前元素已经存在于`set`中,则说明该元素属于交集,将该元素加入结果集中。 -3. 结果集也采用`set`类型,因为需要去重。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public int[] intersection(int[] nums1, int[] nums2) { - var results = new HashSet(); - var num1Set = new HashSet(); - - for (var num : nums1) { - num1Set.add(num); - } - - for (var num : nums2) { - if (num1Set.contains(num)) { - results.add(num); - } - } - - return results.stream().mapToInt(num -> num).toArray(); - } -} -``` - -## Python - -```python -class Solution: - def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: - set_of_nums1 = set(nums1) - results = set() - - for num in nums2: - if num in set_of_nums1: - results.add(num) - - return list(results) -``` - -## C++ - -```cpp -class Solution { -public: - vector intersection(vector& nums1, vector& nums2) { - unordered_set results; - unordered_set set_of_nums1(nums1.begin(), nums1.end()); - - for (auto num : nums2) { - if (set_of_nums1.contains(num)) { - results.insert(num); - } - } - - return vector(results.begin(), results.end()); - } -}; -``` - -## JavaScript - -```javascript -var intersection = function (nums1, nums2) { - let results = new Set() - let num1Set = new Set(nums1) - - for (const num of nums2) { - if (num1Set.has(num)) { - results.add(num) - } - } - - return Array.from(results) -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] Intersection(int[] nums1, int[] nums2) - { - var results = new HashSet(); - var num1Set = new HashSet(); - - foreach (int num in nums1) - num1Set.Add(num); - - foreach (int num in nums2) - { - if (num1Set.Contains(num)) - { - results.Add(num); - } - } - - return results.ToArray(); - } -} -``` - -## Go - -```go -func intersection(nums1 []int, nums2 []int) []int { - results := map[int]bool{} - num1Set := map[int]bool{} - - for _, num := range nums1 { - num1Set[num] = true - } - - for _, num := range nums2 { - if _, ok := num1Set[num]; ok { - results[num] = true - } - } - - return slices.Collect(maps.Keys(results)) -} -``` - -## Ruby - -```ruby -def intersection(nums1, nums2) - nums1_set = Set.new(nums1) - results = Set.new - - nums2.each do |num| - if nums1_set.include?(num) - results << num - end - end - - results.to_a -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[349. 两个数组的交集 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/349-intersection-of-two-arrays). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/377-combination-sum-iv.md b/zh/1-1000/377-combination-sum-iv.md deleted file mode 100644 index 9bd1a16..0000000 --- a/zh/1-1000/377-combination-sum-iv.md +++ /dev/null @@ -1,192 +0,0 @@ -# 377. Combination Sum IV -LeetCode link: [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) - -## LeetCode problem description -> Given an array of **distinct** integers `nums` and a target integer `target`, return the number of possible combinations that add up to `target`. - -The test cases are generated so that the answer can fit in a 32-bit integer. - -``` -Example 1: - -Input: nums = [1,2,3], target = 4 -Output: 7 - -Explanation: -The possible combination ways are: -(1, 1, 1, 1) -(1, 1, 2) -(1, 2, 1) -(1, 3) -(2, 1, 1) -(2, 2) -(3, 1) -Note that different sequences are counted as different combinations. ------------------------------------------------------------------------- - -Example 2: - -Input: nums = [9], target = 3 -Output: 0 - ------------------------------------------------------------------------- - -Constraints: - -1 <= nums.length <= 200 -1 <= nums[i] <= 1000 -All the elements of 'nums' are 'unique'. -1 <= target <= 1000 -``` - -## Thoughts -This is `Unbounded Knapsack Problem` A, and it also requires us to consider the sequences. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int CombinationSum4(int[] nums, int target) - { - var dp = new int[target + 1]; - dp[0] = 1; - - for (var i = 1; i < dp.Length; i++) - { - foreach (var num in nums) - { - if (i >= num) - { - dp[i] += dp[i - num]; - } - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def combinationSum4(self, nums: List[int], target: int) -> int: - dp = [0] * (target + 1) - dp[0] = 1 - - for i in range(1, len(dp)): - for num in nums: - if i >= num: - dp[i] += dp[i - num] - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int combinationSum4(vector& nums, int target) { - vector dp(target + 1, 0); - dp[0] = 1; - - for (auto i = 1; i < dp.size(); i++) { - for (auto num : nums) { - if (i >= num) { - dp[i] += dp[i - num]; - } - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int combinationSum4(int[] nums, int target) { - var dp = new int[target + 1]; - dp[0] = 1; - - for (var i = 1; i < dp.length; i++) { - for (var num : nums) { - if (i >= num) { - dp[i] += dp[i - num]; - } - } - } - - return dp[target]; - } -} -``` - -## JavaScript -```javascript -var combinationSum4 = function (nums, target) { - const dp = Array(target + 1).fill(0) - dp[0] = 1 - - for (let i = 1; i < dp.length; i++) { - for (const num of nums) { - if (i >= num) { - dp[i] += dp[i - num] - } - } - } - - return dp.at(-1) -}; -``` - -## Go -```go -func combinationSum4(nums []int, target int) int { - dp := make([]int, target + 1) - dp[0] = 1 - - for i := 1; i < len(dp); i++ { - for _, num := range nums { - if i >= num { - dp[i] += dp[i - num] - } - } - } - - return dp[target] -} -``` - -## Ruby -```ruby -def combination_sum4(nums, target) - dp = Array.new(target + 1, 0) - dp[0] = 1 - - (1...dp.size).each do |i| - nums.each do |num| - dp[i] += dp[i - num] if i >= num - end - end - - return dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/383-ransom-note.md b/zh/1-1000/383-ransom-note.md deleted file mode 100644 index 1ef9177..0000000 --- a/zh/1-1000/383-ransom-note.md +++ /dev/null @@ -1,252 +0,0 @@ -# 383. 赎金信 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[383. 赎金信 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/383-ransom-note),体验更佳! - -力扣链接:[383. 赎金信](https://leetcode.cn/problems/ransom-note), 难度等级:**简单**。 - -## LeetCode “383. 赎金信”问题描述 - -给你两个字符串:`ransomNote` 和 `magazine` ,判断 `ransomNote` 能不能由 `magazine` 里面的字符构成。 - -如果可以,返回 `true` ;否则返回 `false` 。 - -`magazine` 中的每个字符只能在 `ransomNote` 中使用一次。 - -### [示例 1] - -**输入**: `ransomNote = "a", magazine = "b"` - -**输出**: `false` - -### [示例 2] - -**输入**: `ransomNote = "aa", magazine = "ab"` - -**输出**: `false` - -### [示例 3] - -**输入**: `ransomNote = "aa", magazine = "aab"` - -**输出**: `true` - -### [约束] - -- `1 <= ransomNote.length, magazine.length <= 10^5` -- `ransomNote` 和 `magazine` 由小写英文字母组成 - -## 思路 - -1. 本题等同于求`magazine`是否能包含`ransomNote`中的所有字符。 -2. 先对`magazine`进行统计,得出每个字符对应的字数,结果存储在`Map`中。每一次都是一个加一的操作。 -3. 下一步做什么? -
点击查看答案

遍历`ransomNote`,对当前字符对应的数量进行减一操作(反向操作)。如果某个字符的数量小于0,则返回`false`。

- -## 步骤 - -1. 先对`magazine`进行字符和字数统计,结果存储在`Map`中。 - - ```javascript - charToCount = new Map() - - for (character in magazine) { - charToCount[character] += 1 - } - ``` - -2. 然后,遍历`ransomNote`,并对`Map`中的数据进行反向操作。如果某个字符的字数小于0,则返回`false`。 - - ```javascript - charToCount = new Map() - - for (character in magazine) { - charToCount[character] += 1 - } - - for (character in ransomNote) { - charToCount[character] -= 1 - - if (charToCount[character] < 0) { - return false - } - } - - return true - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public boolean canConstruct(String ransomNote, String magazine) { - var charToCount = new HashMap(); - - for (var character : magazine.toCharArray()) { - charToCount.put(character, charToCount.getOrDefault(character, 0) + 1); - } - - for (var character : ransomNote.toCharArray()) { - charToCount.put(character, charToCount.getOrDefault(character, 0) - 1); - - if (charToCount.get(character) < 0) { - return false; - } - } - - return true; - } -} -``` - -## Python - -```python -# from collections import defaultdict - -class Solution: - def canConstruct(self, ransomNote: str, magazine: str) -> bool: - char_to_count = defaultdict(int) - - for char in magazine: - char_to_count[char] += 1 - - for char in ransomNote: - char_to_count[char] -= 1 - - if char_to_count[char] < 0: - return False - - return True -``` - -## JavaScript - -```javascript -var canConstruct = function (ransomNote, magazine) { - const charToCount = new Map() - - for (const character of magazine) { - charToCount.set(character, (charToCount.get(character) || 0) + 1) - } - - for (const character of ransomNote) { - charToCount.set(character, (charToCount.get(character) || 0) - 1) - - if (charToCount.get(character) < 0) { - return false - } - } - - return true -}; -``` - -## C# - -```csharp -public class Solution -{ - public bool CanConstruct(string ransomNote, string magazine) - { - var charToCount = new Dictionary(); - - foreach (char character in magazine) - charToCount[character] = charToCount.GetValueOrDefault(character, 0) + 1; - - foreach (char character in ransomNote) - { - charToCount[character] = charToCount.GetValueOrDefault(character, 0) - 1; - - if (charToCount[character] < 0) - { - return false; - } - } - - return true; - } -} -``` - -## Ruby - -```ruby -def can_construct(ransom_note, magazine) - char_to_count = Hash.new(0) - - magazine.each_char { |c| char_to_count[c] += 1 } - - ransom_note.each_char do |c| - char_to_count[c] -= 1 - return false if char_to_count[c] < 0 - end - - true -end -``` - -## Go - -```go -func canConstruct(ransomNote string, magazine string) bool { - charToCount := make(map[rune]int) - - for _, char := range magazine { - charToCount[char]++ - } - - for _, char := range ransomNote { - charToCount[char]-- - - if charToCount[char] < 0 { - return false - } - } - - return true -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canConstruct(string ransomNote, string magazine) { - unordered_map char_to_count; - - for (char character : magazine) { - char_to_count[character]++; - } - - for (char character : ransomNote) { - char_to_count[character]--; - - if (char_to_count[character] < 0) { - return false; - } - } - - return true; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[383. 赎金信 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/383-ransom-note). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/392-is-subsequence.md b/zh/1-1000/392-is-subsequence.md deleted file mode 100644 index a4fdbc6..0000000 --- a/zh/1-1000/392-is-subsequence.md +++ /dev/null @@ -1,518 +0,0 @@ -# 392. 判断子序列 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[392. 判断子序列 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/392-is-subsequence),体验更佳! - -力扣链接:[392. 判断子序列](https://leetcode.cn/problems/is-subsequence), 难度等级:**中等**。 - -## LeetCode “392. 判断子序列”问题描述 - -给定字符串 **s** 和 **t** ,判断 **s** 是否为 **t** 的子序列。 - -字符串的一个**子序列**是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,`"ace"`是`"abcde"`的一个子序列,而`"aec"`不是)。 - -**进阶**: - -如果有大量输入的 `S`,称作 `S1, S2, ... , Sk` 其中 `k >= 10亿`,你需要依次检查它们是否为 `T` 的子序列。在这种情况下,你会怎样改变代码? - -### [示例 1] - -**输入**: `s = "abc", t = "ahbgdc"` - -**输出**: `true` - -### [示例 2] - -**输入**: `s = "axc", t = "ahbgdc"` - -**输出**: `false` - -### [约束] - -- `0 <= s.length <= 100` -- `0 <= t.length <= 10^4` -- `s` and `t` consist only of lowercase English letters. - -## 思路 1 - -- 定义两个指针,最初分别指向两个字符串的头部,字符用`t[i]`, `s[j]`引用。 -- 在对`t`的遍历过程中,`i`自动加1,如果`t[i] == s[j]`,则`j += 1`。 -- 如果`j >= s.length`,返回`true`。如果遍历完`t`了,仍然没有提前返回`true`,则返回`false`。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Python - -```python -class Solution: - def isSubsequence(self, s: str, t: str) -> bool: - if s == "": - return True - - s_index = 0 - - for i in range(len(t)): - if t[i] == s[s_index]: - s_index += 1 - - if s_index >= len(s): - return True - - return False -``` - -## C++ - -```cpp -class Solution { -public: - bool isSubsequence(string s, string t) { - if (s.empty()) { - return true; - } - - int s_index = 0; - - for (int i = 0; i < t.length(); i++) { - if (t[i] == s[s_index]) { - s_index++; - - if (s_index >= s.length()) { - return true; - } - } - } - - return false; - } -}; -``` - -## Java - -```java -class Solution { - public boolean isSubsequence(String s, String t) { - if (s.isEmpty()) { - return true; - } - - int sIndex = 0; - - for (int i = 0; i < t.length(); i++) { - if (t.charAt(i) == s.charAt(sIndex)) { - sIndex++; - - if (sIndex >= s.length()) { - return true; - } - } - } - - return false; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public bool IsSubsequence(string s, string t) - { - if (string.IsNullOrEmpty(s)) - { - return true; - } - - int sIndex = 0; - - for (int i = 0; i < t.Length; i++) - { - if (t[i] == s[sIndex]) - { - sIndex++; - - if (sIndex >= s.Length) - { - return true; - } - } - } - - return false; - } -} -``` - -## Go - -```go -func isSubsequence(s string, t string) bool { - if len(s) == 0 { - return true - } - - sIndex := 0 - - for i := 0; i < len(t); i++ { - if t[i] == s[sIndex] { - sIndex++ - - if sIndex >= len(s) { - return true - } - } - } - - return false -} -``` - -## JavaScript - -```javascript -/** - * @param {string} s - * @param {string} t - * @return {boolean} - */ -var isSubsequence = function(s, t) { - if (s.length === 0) { - return true; - } - - let sIndex = 0; - - for (let i = 0; i < t.length; i++) { - if (t[i] === s[sIndex]) { - sIndex++; - - if (sIndex >= s.length) { - return true; - } - } - } - - return false; -}; -``` - -## Ruby - -```ruby -# @param {String} s -# @param {String} t -# @return {Boolean} -def is_subsequence(s, t) - return true if s.empty? - - s_index = 0 - - t.each_char.with_index do |char, i| - if char == s[s_index] - s_index += 1 - return true if s_index >= s.length - end - end - - false -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -- `题解1`本质上是用`滚动变量`实现的“动态规划”算法。它很好理解,并且空间复杂度降到了`O(1)`。 -- 但现在,我们不仅不做降维,还要升维。理解和实现起来都会更困难些。那为什么还要做这种吃力不讨好的事情呢? -
点击查看答案

因为它能处理一类在动态规划中常见的、更为复杂的场景。比如:[583. 两个字符串的删除操作](583-delete-operation-for-two-strings.md) 等。

-- 本题用一维的滚动数组实现“动态规划”算法,可以吗? -
点击查看答案

当然可以,但考虑本题`一维的滚动数组`不如`二维数组`好理解,实现的过程也容易出错,所以我没有给出相关的代码实现。如何你有兴趣,可以尝试下。

-- **比较两个字符串**的题目,属于处理“两个对等数组”,类似的题目做过多次后,我们会形成使用`二维数组`进行动态规划的直觉。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 步骤 - -1. 确定 `dp[i][j]` 的**含义**。 - - `dp[i][j]` 表示 `s` 的前 `i` 个字母是否是 `t` 的前 `j` 个字母的子序列。 - - `dp[i][j]` 为 `true` 或 `false`。 -2. 确定 `dp` 数组的初始值。 - - 使用示例: - - ``` - After initialization, the 'dp' array would be: - s = "abc", t = "ahbgdc" - # a h b g d c - # T T T T T T T # dp[0] - # a F F F F F F F - # b F F F F F F F - # c F F F F F F F - ``` - - `dp[0][j] = true` 因为 `dp[0]` 表示空字符串,而空字符串是任何字符串的子序列。 - - `dp[i][j] = false (i != 0)`。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - ``` - 1. s = "a", t = "ahbgdc" - # a h b g d c - # T T T T T T T - # a F T T T T T T # dp[1] - ``` - ``` - 2. s = "ab", t = "ahbgdc" - # a h b g d c - # T T T T T T T - # a F T T T T T T - # b F F F T T T T - ``` - ``` - 3. s = "abc", t = "ahbgdc" - # a h b g d c - # T T T T T T T - # a F T T T T T T - # b F F F T T T T - # c F F F F F F T # dp[3] - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```ruby - if s[i - 1] == t[j - 1] - dp[i][j] = dp[i - 1][j - 1] - else - dp[i][j] = dp[i][j - 1] - end - ``` -5. 检查 `dp` 数组的值 - - 打印 `dp` 以查看它是否符合预期。 - -## 复杂度 - -- 时间复杂度: `O(N * M)`. -- 空间复杂度: `O(N * M)`. - -## Python - -```python -class Solution: - def isSubsequence(self, s: str, t: str) -> bool: - column_count = len(t) + 1 - dp = [[True] * column_count] - for _ in s: - dp.append([False] * column_count) - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if s[i - 1] == t[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = dp[i][j - 1] - - return dp[-1][-1] -``` - -## C++ - -```cpp -class Solution { -public: - bool isSubsequence(string s, string t) { - vector> dp(s.size() + 1, vector(t.size() + 1)); - fill(dp[0].begin(), dp[0].end(), true); - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (s[i - 1] == t[j - 1]) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = dp[i][j - 1]; - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript - -```javascript -var isSubsequence = function (s, t) { - const dp = Array(s.length + 1).fill().map( - () => Array(t.length + 1).fill(false) - ) - dp[0].fill(true) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (s[i - 1] == t[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = dp[i][j - 1] - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go - -```go -func isSubsequence(s string, t string) bool { - dp := make([][]bool, len(s) + 1) - columnSize := len(t) + 1 - dp[0] = slices.Repeat([]bool{true}, columnSize) - for i := 1; i < len(dp); i++ { - dp[i] = make([]bool, columnSize) - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if s[i - 1] == t[j - 1] { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = dp[i][j - 1] - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Java - -```java -class Solution { - public boolean isSubsequence(String s, String t) { - var dp = new boolean[s.length() + 1][t.length() + 1]; - Arrays.fill(dp[0], true); - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (s.charAt(i - 1) == t.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = dp[i][j - 1]; - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public bool IsSubsequence(string s, string t) - { - var dp = new bool[s.Length + 1, t.Length + 1]; - for (var j = 0; j < dp.GetLength(1); j++) - dp[0, j] = true; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (s[i - 1] == t[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1]; - } - else - { - dp[i, j] = dp[i, j - 1]; - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Ruby - -```ruby -def is_subsequence(s, t) - dp = Array.new(s.size + 1) do |i| - Array.new(t.size + 1, i == 0 ? true : false) - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if s[i - 1] == t[j - 1] - dp[i - 1][j - 1] - else - dp[i][j - 1] - end - end - end - - dp[-1][-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[392. 判断子序列 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/392-is-subsequence). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/416-partition-equal-subset-sum.md b/zh/1-1000/416-partition-equal-subset-sum.md deleted file mode 100644 index ba2e232..0000000 --- a/zh/1-1000/416-partition-equal-subset-sum.md +++ /dev/null @@ -1,602 +0,0 @@ -# 416. 分割等和子集 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[416. 分割等和子集 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/416-partition-equal-subset-sum),体验更佳! - -力扣链接:[416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum), 难度等级:**中等**。 - -## LeetCode “416. 分割等和子集”问题描述 - -给你一个 **只包含正整数** 的 **非空** 数组 `nums` 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 - -### [示例 1] - -**输入**: `nums = [1,5,11,5]` - -**输出**: `true` - -**解释**: `数组可以分割成 [1, 5, 5] 和 [11] 。` - -### [示例 2] - -**输入**: `nums = [1,2,3,5]` - -**输出**: `false` - -**解释**: `数组不能分割成两个元素和相等的子集。` - -### [约束] - -- `1 <= nums.length <= 200` -- `1 <= nums[i] <= 100` - -## 思路 1 - -- 第一次看到这道题,我们可能想循环遍历数组的所有子集,如果有一个子集的和等于`和的一半`,就返回`true`。这可以用`回溯算法`来实现,但是看到`nums.length <= 200`这个约束,我们估计程序会超时。 -- 本题可用`0/1背包问题`算法来解。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## “0/1背包问题”的模式 - -典型的“0/1背包问题”,指每个“物品”只能使用一次,来填充“背包”。“物品”有“重量”和“价值”属性,求“背包”能存放的“物品”的最大价值。 - -其特点是:有**一组数字**,每个数字只能被使用一次,通过某种计算得到**另一个数字**。问题也可以变成能否得到?有多少种变化?等。 - -因为“0/1背包问题”属于“动态规划”,所以我会用“动态规划”的模式讲解。 - -1. 确定数组`dp`的每个值代表的含义。 - - 首选**一维滚动数组**,代码简洁。 - - 确定什么是“物品”,什么是“背包”。 - - 如果`dp[j]`是一个布尔值,则`dp[j]`表示是否可以前`i`个`物品`的`和`得到`j`。 - - 如果`dp[j]`是一个数值,则`dp[j]`表示是利用前`i`个`物品`,`dp[j]`能达到的所求问题的极限值。 -2. 初始化数组`dp`的值。 - - 确定“背包”的大小。需要让背包大小再加1,即插入`dp[0]`做为起始点,方便理解和引用。 - - `dp[0]`有时需要特殊处理。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - 先在外层循环中,**遍历物品**。 - - 后在内层循环中,**遍历背包大小**。 - - 在遍历背包大小时,由于`dp[j]`取决于`dp[j]`和`dp[j - weights[i]]`,因此我们应该**从右到左**遍历`dp`数组。 - - 请思考是否可以从`从左到右`遍历`dp`数组? -4. 根据`dp`网格数据,推导出“递推公式”。 - - 如果`dp[j]`是一个布尔值: - - ```cpp - dp[j] = dp[j] || dp[j - weights[i]] - ``` - - 如果`dp[j]`是一个数值: - - ```cpp - dp[j] = min_or_max(dp[j], dp[j - weights[i]] + values[i]) - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 步骤 - -1. 确定`dp[j]`的**含义** - - `dp[j]`表示是否前`i`个`nums`的`和`是否等于`j`。 - - `dp[j]`是一个布尔值。 -2. 确定 `dp` 数组的初始值 - - 举个例子: - - ``` - nums = [1,5,11,5],所以 '和的一半' 是 11。 - 背包的 `size` 是 '11 + 1',`物品` 是 `nums`。 - 所以初始化后,'dp' 数组将是: - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F # dp - # 1 - # 5 - # 11 - # 5 - ``` - - `dp[0]` 设置为 `true`,表示不放任何物品即可得到空背包,另外,它作为起始值,后面的 `dp[j]` 将依赖它。如果为 `false`,则 `dp[j]` 的所有值都将为 `false`。 - - `dp[j] = false (j != 0)`,表示0个 `nums`的和不可能等于 `j`。 - -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - ``` - 1. 使用第一个数字 '1'。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F # dp - ``` - - ``` - 2. 使用第二个数字 '5'。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F - # 5 T T F F F T T F F F F F - ``` - - ``` - 3. 使用第三个数字 '11'。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F - # 5 T T F F F T T F F F F F - # 11 T T F F F T T F F F F T - ``` - - ``` - 3. 使用最后一个数字“5”。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 1 T T F F F F F F F F F F - # 5 T T F F F T T F F F F F - # 11 T T F F F T T F F F F T - # 5 T T F F F T T F F F T T # dp - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```cpp - dp[j] = dp[j] || dp[j - nums[i]] - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 复杂度 - -- 时间复杂度: `O(n * sum/2)`. -- 空间复杂度: `O(sum/2)`. - -## Python - -```python -class Solution: - def canPartition(self, nums: List[int]) -> bool: - sum_ = sum(nums) - - if sum_ % 2 == 1: - return False - - dp = [False] * ((sum_ // 2) + 1) - dp[0] = True - - for num in nums: - # If not traversing in reverse order, the newly assigned value `dp[j]` will act as `dp[j - num]` later, - # then the subsequent `dp[j]` will be affected. But each `num` can only be used once! - j = len(dp) - 1 - while j >= num: - dp[j] = dp[j] or dp[j - num] - j -= 1 - - return dp[-1] -``` - -## C# - -```csharp -public class Solution -{ - public bool CanPartition(int[] nums) - { - int sum = nums.Sum(); - - if (sum % 2 == 1) - return false; - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (var num in nums) - { - for (var j = dp.GetUpperBound(0); j >= num; j--) - { - dp[j] = dp[j] || dp[j - num]; - } - } - - return dp.Last(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canPartition(vector& nums) { - auto sum = reduce(nums.begin(), nums.end()); - - if (sum % 2 == 1) { - return false; - } - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto num : nums) { - for (auto j = dp.size() - 1; j >= num; j--) { - dp[j] = dp[j] || dp[j - num]; - } - } - - return dp.back(); - } -}; -``` - -## Java - -```java -class Solution { - public boolean canPartition(int[] nums) { - var sum = IntStream.of(nums).sum(); - - if (sum % 2 == 1) { - return false; - } - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var num : nums) { - for (var j = dp.length - 1; j >= num; j--) { - dp[j] = dp[j] || dp[j - num]; - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript - -```javascript -var canPartition = function (nums) { - const sum = _.sum(nums) - - if (sum % 2 == 1) { - return false - } - - const dp = Array(sum / 2 + 1).fill(false) - dp[0] = true - - for (const num of nums) { - for (let j = dp.length - 1; j >= num; j--) { - dp[j] = dp[j] || dp[j - num] - } - } - - return dp.at(-1) -}; -``` - -## Go - -```go -func canPartition(nums []int) bool { - sum := 0 - for _, num := range nums { - sum += num - } - - if sum % 2 == 1 { - return false - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, num := range nums { - for j := len(dp) - 1; j >= num; j-- { - dp[j] = dp[j] || dp[j - num] - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby - -```ruby -def can_partition(nums) - sum = nums.sum - - return false if sum % 2 == 1 - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - nums.each do |num| - (num...dp.size).reverse_each do |j| - dp[j] = dp[j] || dp[j - num] - end - end - - dp[-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -在*方案 1*中,遍历顺序是 **从右到左**,这真的很重要。 - -面试的时候,你需要记住它。有什么办法可以不用担心遍历顺序? - -
点击查看答案

只要把原`dp`复制一份,并引用复制品的值,就不用担心原`dp`值被修改了。

- -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 复杂度 - -- 时间复杂度: `O(n * sum/2)`. -- 空间复杂度: `O(n * sum/2)`. - -## Python - -```python -class Solution: - def canPartition(self, nums: List[int]) -> bool: - sum_ = sum(nums) - - if sum_ % 2 == 1: - return False - - dp = [False] * ((sum_ // 2) + 1) - dp[0] = True - - for num in nums: - # Make a copy of the 'dp' that has not been modified to eliminate distractions. - dc = dp.copy() - - for j in range(num, len(dp)): # any order is fine - dp[j] = dc[j] or dc[j - num] # Use 'dc' instead of 'dp' because 'dp' will be modified. - - return dp[-1] -``` - -## C# - -```csharp -public class Solution -{ - public bool CanPartition(int[] nums) - { - int sum = nums.Sum(); - - if (sum % 2 == 1) - return false; - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (var num in nums) - { - var dc = (bool[])dp.Clone(); - - for (var j = num; j < dp.Length; j++) - { - dp[j] = dc[j] || dc[j - num]; - } - } - - return dp.Last(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canPartition(vector& nums) { - auto sum = reduce(nums.begin(), nums.end()); - - if (sum % 2 == 1) { - return false; - } - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto num : nums) { - auto dc = dp; - - for (auto j = num; j < dp.size(); j++) { - dp[j] = dc[j] || dc[j - num]; - } - } - - return dp.back(); - } -}; -``` - -## Java - -```java -class Solution { - public boolean canPartition(int[] nums) { - var sum = IntStream.of(nums).sum(); - - if (sum % 2 == 1) { - return false; - } - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var num : nums) { - var dc = dp.clone(); - - for (var j = num; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - num]; - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript - -```javascript -var canPartition = function (nums) { - const sum = _.sum(nums) - - if (sum % 2 == 1) { - return false - } - - const dp = Array(sum / 2 + 1).fill(false) - dp[0] = true - - for (const num of nums) { - const dc = [...dp] - - for (let j = num; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - num] - } - } - - return dp.at(-1) -}; -``` - -## Go - -```go -func canPartition(nums []int) bool { - sum := 0 - for _, num := range nums { - sum += num - } - - if sum % 2 == 1 { - return false - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, num := range nums { - dc := slices.Clone(dp) - - for j := num; j < len(dp); j++ { - dp[j] = dc[j] || dc[j - num] - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby - -```ruby -def can_partition(nums) - sum = nums.sum - - return false if sum % 2 == 1 - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - nums.each do |num| - dc = dp.clone - - (num...dp.size).each do |j| - dp[j] = dc[j] || dc[j - num] - end - end - - dp[-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[416. 分割等和子集 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/416-partition-equal-subset-sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/42-trapping-rain-water.md b/zh/1-1000/42-trapping-rain-water.md deleted file mode 100644 index 153b6f4..0000000 --- a/zh/1-1000/42-trapping-rain-water.md +++ /dev/null @@ -1,263 +0,0 @@ -# 42. Trapping Rain Water (Monotonic Stack) -LeetCode link: [42. Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) - -## LeetCode problem description -Given `n` non-negative integers representing an elevation map where the width of each bar is `1`, compute how much water it can trap after raining. - -### Example 1 -![](../../images/examples/42_1.png) -``` -Input: height = [0,1,0,2,1,0,1,3,2,1,2,1] -Output: 6 - -Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. -In this case, 6 units of rain water (blue section) are being trapped. -``` - -### Example 2 -``` -Input: height = [4,2,0,3,2,5] -Output: 9 -``` - -### Constraints -- `n == height.length` -- `1 <= n <= 2 * 10000` -- `0 <= height[i] <= 100000` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -This solution will follow **Monotonic Stack**'s common rule: **only calculating when `pop()` is happening**. - -This common rule can be applied to calculating result for **most** of the **Monotonic Stack** problems. - -![](../../images/42.png) - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Java -```java -class Solution { - public int trap(int[] heights) { - var result = 0; - var indexStack = new Stack(); - - for (var i = 0; i < heights.length; i++) { - while (!indexStack.empty() && heights[indexStack.peek()] <= heights[i]) { - var poppedIndex = indexStack.pop(); - - if (indexStack.empty()) { - break; - } - - var leftHeight = heights[indexStack.peek()]; - var rightHeight = heights[i]; - var heightGap = Math.min(leftHeight, rightHeight) - heights[poppedIndex]; - var width = i - indexStack.peek() - 1; - result += heightGap * width; - } - - indexStack.push(i); - } - - return result; - } -} -``` - -## Python -```python -class Solution: - def trap(self, heights: List[int]) -> int: - result = 0 - index_stack = [] - - for i, height in enumerate(heights): - while index_stack and heights[index_stack[-1]] <= height: - popped_index = index_stack.pop() - - if not index_stack: - break - - left_height = heights[index_stack[-1]] - right_height = height - height_gap = min(left_height, right_height) - heights[popped_index] - width = i - index_stack[-1] - 1 - result += height_gap * width - - index_stack.append(i) - - return result -``` - -![](../../images/42.png) - -## C++ -```cpp -class Solution { -public: - int trap(vector& heights) { - auto result = 0; - stack index_stack; - - for (auto i = 0; i < heights.size(); i++) { - auto previous_height = 0; - - while (!index_stack.empty() && heights[index_stack.top()] <= heights[i]) { - auto popped_index = index_stack.top(); - index_stack.pop(); - - if (index_stack.empty()) { - break; - } - - auto left_height = heights[index_stack.top()]; - auto right_height = heights[i]; - auto height_gap = min(left_height, right_height) - heights[popped_index]; - auto width = i - index_stack.top() - 1; - result += height_gap * width; - } - - index_stack.push(i); - } - - return result; - } -}; -``` - -## JavaScript -```javascript -var trap = function (heights) { - let result = 0 - const indexStack = [] - - heights.forEach((height, i) => { - while (indexStack.length > 0 && heights[indexStack.at(-1)] <= height) { - const poppedIndex = indexStack.pop() - - if (indexStack.length === 0) { - break - } - - const leftHeight = heights[indexStack.at(-1)] - const rightHeight = heights[i] - const heightGap = Math.min(leftHeight, rightHeight) - heights[poppedIndex] - const width = i - indexStack.at(-1) - 1 - result += heightGap * width - } - - indexStack.push(i) - }) - - return result -}; -``` - -![](../../images/42.png) - -## C# -```c# -public class Solution -{ - public int Trap(int[] heights) - { - int result = 0; - var indexStack = new Stack(); - - for (var i = 0; i < heights.Length; i++) - { - while (indexStack.Count > 0 && heights[indexStack.Peek()] <= heights[i]) - { - int poppedIndex = indexStack.Pop(); - - if (indexStack.Count == 0) - { - break; - } - - int leftHeight = heights[indexStack.Peek()]; - int rightHeight = heights[i]; - int heightGap = Math.Min(leftHeight, rightHeight) - heights[poppedIndex]; - int width = i - indexStack.Peek() - 1; - result += heightGap * width; - } - - indexStack.Push(i); - } - - return result; - } -} -``` - -## Go -```go -func trap(heights []int) int { - result := 0 - indexStack := []int{} - - for i, height := range heights { - for len(indexStack) > 0 && heights[indexStack[len(indexStack) - 1]] <= height { - poppedIndex := indexStack[len(indexStack) - 1] - indexStack = indexStack[:len(indexStack) - 1] - - if len(indexStack) == 0 { - break - } - - leftIndex := indexStack[len(indexStack) - 1] - leftHeight := heights[leftIndex] - rightHeight := heights[i] - heightGap := min(leftHeight, rightHeight) - heights[poppedIndex] - width := i - leftIndex - 1 - result += heightGap * width - } - - indexStack = append(indexStack, i) - } - - return result -} -``` - -![](../../images/42.png) - -## Ruby -```ruby -def trap(heights = []) - result = 0 - index_stack = [] - - heights.each_with_index do |height, i| - while !index_stack.empty? && heights[index_stack.last] <= height - popped_index = index_stack.pop - - break if index_stack.empty? - - left_height = heights[index_stack.last] - right_height = heights[i] - height_gap = [ left_height, right_height ].min - heights[popped_index] - width = i - index_stack.last - 1 - result += height_gap * width - end - - index_stack << i - end - - result -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/433-minimum-genetic-mutation.md b/zh/1-1000/433-minimum-genetic-mutation.md deleted file mode 100644 index dd490ca..0000000 --- a/zh/1-1000/433-minimum-genetic-mutation.md +++ /dev/null @@ -1,217 +0,0 @@ -# 433. Minimum Genetic Mutation - Best Practices of LeetCode Solutions -LeetCode link: [433. Minimum Genetic Mutation](https://leetcode.com/problems/minimum-genetic-mutation), difficulty: **Medium**. - -## LeetCode description of "433. Minimum Genetic Mutation" -A gene string can be represented by an 8-character long string, with choices from `A`, `C`, `G`, and `T`. - -Suppose we need to investigate a mutation from a gene string `startGene` to a gene string `endGene` where one mutation is defined as one single character changed in the gene string. - -* For example, `"AACCGGTT" --> "AACCGGTA"` is one mutation. - -There is also a gene bank `bank` that records all the valid gene mutations. A gene must be in `bank` to make it a valid gene string. - -Given the two gene strings `startGene` and `endGene` and the gene bank `bank`, return _the minimum number of mutations needed to mutate from `startGene` to `endGene`_. If there is no such a mutation, return `-1`. - -Note that the starting point is assumed to be valid, so it might not be included in the bank. - -### [Example 1] -**Input**: `startGene = "AACCGGTT", endGene = "AACCGGTA", bank = ["AACCGGTA"]` - -**Output**: `1` - -### [Example 2] -**Input**: `startGene = "AACCGGTT", endGene = "AAACGGTA", bank = ["AACCGGTA","AACCGCTA","AAACGGTA"]` - -**Output**: `2` - -### [Constraints] -- `0 <= bank.length <= 10` -- `startGene.length == endGene.length == bank[i].length == 8` -- `startGene`, `endGene`, and `bank[i]` consist of only the characters `['A', 'C', 'G', 'T']`. - -## Intuition 1 -We can think of this problem as a shortest path problem on a graph: there are `4^8` vertices (strings `'AAAAAAAA'` to `'TTTTTTTT'`), and there is an edge between two vertices if they differ in one character, and if *both* vertices are in `bank`. - -So this issue can be solved by **Breadth-First Search** on a undirected graph. - -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **Breadth-First Search** can be thought of as visiting vertices in rounds and rounds. Actually, whenever you see a question is about - getting `minimum number` of something of a graph, `Breadth-First Search` would probably help. - -* `Breadth-First Search` emphasizes first-in-first-out, so a **queue** is needed. - -### Approach 1: Breadth-First Search Algorithm -1. `Breadth-First Search` a graph means traversing **from near to far**, from `circle 1` to `circle N`. Each `circle` is a round of iteration. -1. So through `Breadth-First Search`, when a word matches `endGene`, the game is over, and we can return the number of **circle** as a result. - -### Complexity -> **N** is the length of `bank`. - -* Time: `O((8 * 4) * N)`. -* Space: `O(N)`. - -## Approach 2: A* (A-Star) Search Algorithm - -**A-Star Search Algorithm** can be used to greatly improve the performance of **Breadth-First Search Algorithm**. - -Please view detailed **A-Star Algorithm** at [752. Open the Lock](./752-open-the-lock.md). - -Bellow has code using _A-Star Search Algorithm_ in Python. - -## Python -### Approach 1: Breadth-First Search (way 1) -```python -class Solution: - def minMutation(self, start_gene: str, end_gene: str, bank: List[str]) -> int: - if not end_gene in bank: - return -1 - - self.end_gene = end_gene - self.bank = set(bank) - self.queue = deque([start_gene]) # difference 1 - result = 0 - - while self.queue: - result += 1 # difference 2 - queue_size = len(self.queue) - - for i in range(queue_size): # difference 3 - gene = self.queue.popleft() - - if self.mutate_one(gene): - return result - - return -1 - - def mutate_one(self, gene): # difference 4 - for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: - if gene[i] == char: - continue - - mutation = f'{gene[:i]}{char}{gene[i + 1:]}' - - if mutation == self.end_gene: - return True - - if mutation in self.bank: - self.queue.append(mutation) - self.bank.remove(mutation) -``` - -### Approach 1: Breadth-First Search (way 2 by adding `mutated_count` in queue's item) -```python -class Solution: - def minMutation(self, start_gene: str, end_gene: str, bank: List[str]) -> int: - if not end_gene in bank: - return -1 - - self.bank = set(bank) - self.end_gene = end_gene - self.queue = deque([(start_gene, 0)]) # difference 1 - - while self.queue: - gene, mutated_count = self.queue.popleft() # difference 2 - - if self.mutate_one(gene, mutated_count): - return mutated_count + 1 - - return -1 - - def mutate_one(self, gene, mutated_count): # difference 3 - for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: - if gene[i] == char: - continue - - mutation = f'{gene[:i]}{char}{gene[i + 1:]}' - - if mutation == self.end_gene: - return True - - if mutation in self.bank: - self.queue.append((mutation, mutated_count + 1)) - self.bank.remove(mutation) -``` - -### Approach 2: A* (A-Star) Search Algorithm -```python -import heapq - - -class Solution: - def minMutation(self, start_gene: str, end_gene: str, bank: List[str]) -> int: - if not end_gene in bank: - return -1 - - self.end_gene = end_gene - bank = set(bank) - priority_queue = [(self.distance(start_gene), start_gene, 0)] # difference 1 - - while priority_queue: - _, gene, mutated_count = heapq.heappop(priority_queue) # difference 2 - - for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: - if gene[i] == char: - continue - - mutation = f'{gene[:i]}{char}{gene[i + 1:]}' - - if mutation == end_gene: - return mutated_count + 1 - - if mutation in bank: - heapq.heappush( - priority_queue, - (self.distance(mutation), mutation, mutated_count + 1) - ) # difference 3 - bank.remove(mutation) - - return -1 - - def distance(self, gene): # difference 4 - result = 0 - - for i in range(8): - if gene[i] != self.end_gene[i]: - result += 1 - - return result -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/454-4sum-ii.md b/zh/1-1000/454-4sum-ii.md deleted file mode 100644 index f54ad60..0000000 --- a/zh/1-1000/454-4sum-ii.md +++ /dev/null @@ -1,280 +0,0 @@ -# 454. 四数相加 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[454. 四数相加 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/454-4sum-ii),体验更佳! - -力扣链接:[454. 四数相加 II](https://leetcode.cn/problems/4sum-ii), 难度等级:**中等**。 - -## LeetCode “454. 四数相加 II”问题描述 - -给你四个整数数组 `nums1`、`nums2`、`nums3` 和 `nums4` ,数组长度都是 `n` ,请你计算有多少个元组 `(i, j, k, l)` 能满足: - -- `0 <= i, j, k, l < n` -- `nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0` - -### [示例 1] - -**输入**: `nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]` - -**输出**: `2` - -**解释**: - -

两个元组如下:

- -
    -
  1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
  2. -
  3. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
  4. -
- - -### [示例 2] - -**输入**: `nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]` - -**输出**: `1` - -### [约束] - -- `n == nums1.length` -- `n == nums2.length` -- `n == nums3.length` -- `n == nums4.length` -- `1 <= n <= 200` -- `-2^28 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2^28` - -## 思路 - -1. 因为最终要求是每组数中各取一个数,所以可以把四组数拆分成两个两组数。 -2. 统计出每个`和`值对应的个数。使用`Map`储存,`key`为`和`,`value`为`count`。 -3. 遍历`nums3`和`nums4`,如果`-(num3 + num4)`存在于`Map`的`keys`中,则`count`计入总数。 - -## 步骤 - -1. 统计出每个`和`值对应的个数。使用`Map`储存,`key`为`和`,`value`为`count`。 - - ```python - num_to_count = defaultdict(int) - - for num1 in nums1: - for num2 in nums2: - num_to_count[num1 + num2] += 1 - ``` - -2. 遍历`nums3`和`nums4`,如果`-(num3 + num4)`存在于`Map`的`keys`中,则`count`计入总数。 - - ```python - result = 0 - - for num3 in nums3: - for num4 in nums4: - result += num_to_count[-(num3 + num4)] - - return result - ``` - -## 复杂度 - -- 时间复杂度: `O(N * N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { - var numToCount = new HashMap(); - - for (var num1 : nums1) { - for (var num2 : nums2) { - numToCount.put( - num1 + num2, - numToCount.getOrDefault(num1 + num2, 0) + 1 - ); - } - } - - var result = 0; - - for (var num3 : nums3) { - for (var num4 : nums4) { - result += numToCount.getOrDefault(-(num3 + num4), 0); - } - } - - return result; - } -} -``` - -## Python - -```python -# from collections import defaultdict - -class Solution: - def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int: - num_to_count = defaultdict(int) - - for num1 in nums1: - for num2 in nums2: - num_to_count[num1 + num2] += 1 - - result = 0 - - for num3 in nums3: - for num4 in nums4: - result += num_to_count[-(num3 + num4)] - - return result -``` - -## JavaScript - -```javascript -var fourSumCount = function (nums1, nums2, nums3, nums4) { - const numToCount = new Map() - - for (const num1 of nums1) { - for (const num2 of nums2) { - numToCount.set(num1 + num2, (numToCount.get(num1 + num2) || 0) + 1) - } - } - - let result = 0 - - for (const num3 of nums3) { - for (const num4 of nums4) { - result += numToCount.get(-(num3 + num4)) || 0 - } - } - - return result -}; -``` - -## C# - -```csharp -public class Solution -{ - public int FourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) - { - var numToCount = new Dictionary(); - - foreach (int num1 in nums1) - { - foreach (int num2 in nums2) - { - numToCount[num1 + num2] = numToCount.GetValueOrDefault(num1 + num2, 0) + 1; - } - } - - int result = 0; - - foreach (int num3 in nums3) - { - foreach (int num4 in nums4) - { - result += numToCount.GetValueOrDefault(-(num3 + num4), 0); - } - } - - return result; - } -} -``` - -## Ruby - -```ruby -def four_sum_count(nums1, nums2, nums3, nums4) - num_to_count = Hash.new(0) - - nums1.each do |num1| - nums2.each do |num2| - num_to_count[num1 + num2] += 1 - end - end - - result = 0 - - nums3.each do |num3| - nums4.each do |num4| - result += num_to_count[-(num3 + num4)] - end - end - - result -end -``` - -## Go - -```go -func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int { - // Create map to store sum frequencies from first two arrays - sumCount := make(map[int]int) - - // Calculate all possible sums from nums1 and nums2 - for _, num1 := range nums1 { - for _, num2 := range nums2 { - sumCount[num1 + num2]++ - } - } - - result := 0 - // Check complementary sums from nums3 and nums4 - for _, num3 := range nums3 { - for _, num4 := range nums4 { - // Add count of complementary sum that would make total zero - result += sumCount[-(num3 + num4)] - } - } - - return result -} -``` - -## C++ - -```cpp -class Solution { -public: - int fourSumCount(vector& nums1, vector& nums2, vector& nums3, vector& nums4) { - // Store sum frequencies from first two arrays - unordered_map sumCount; - - // Calculate all possible sums from nums1 and nums2 - for (int num1 : nums1) { - for (int num2 : nums2) { - sumCount[num1 + num2]++; - } - } - - int result = 0; - // Check complementary sums from nums3 and nums4 - for (int num3 : nums3) { - for (int num4 : nums4) { - // Add occurrences of required complement sum - result += sumCount[-(num3 + num4)]; - } - } - - return result; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[454. 四数相加 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/454-4sum-ii). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/459-repeated-substring-pattern.md b/zh/1-1000/459-repeated-substring-pattern.md deleted file mode 100644 index 9f802a0..0000000 --- a/zh/1-1000/459-repeated-substring-pattern.md +++ /dev/null @@ -1,229 +0,0 @@ -# 459. 重复的子字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[459. 重复的子字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/459-repeated-substring-pattern),体验更佳! - -力扣链接:[459. 重复的子字符串](https://leetcode.cn/problems/repeated-substring-pattern), 难度等级:**简单**。 - -## LeetCode “459. 重复的子字符串”问题描述 - -给定一个非空的字符串 `s` ,检查是否可以通过由它的一个子串重复多次构成。 - -### [示例 1] - -**输入**: `s = "abcabcabcabc"` - -**输出**: `true` - -**解释**: `可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)` - -### [示例 2] - -**输入**: `s = "aba"` - -**输出**: `false` - -### [约束] - -- `1 <= s.length <= 10000` -- `s` consists of lowercase English letters. - -## 思路 - -解决本问题的关键是要看清楚一点:通过子串的重复能得到`s`,那么子串的起始字母一定是`s[0]`。 -想明白了这一点,子串的排查范围就大大缩小了。 - -## 复杂度 - -- 时间复杂度: `O(N * N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def repeatedSubstringPattern(self, s: str) -> bool: - for i in range(1, int(len(s) / 2) + 1): - if len(s) % i == 0 and s[:i] * int(len(s) / i) == s: - return True - - return False -``` - -## JavaScript - -```javascript -var repeatedSubstringPattern = function (s) { - for (let i = 1; i <= s.length / 2; i++) { - if (s.length % i != 0) { - continue - } - - if (s.slice(0, i).repeat(s.length / i) == s) { - return true - } - } - - return false -}; -``` - -## Go - -```go -func repeatedSubstringPattern(s string) bool { - n := len(s) - - for i := 1; i <= n/2; i++ { - if n%i == 0 { - substring := s[:i] - repeated := strings.Repeat(substring, n/i) - - if repeated == s { - return true - } - } - } - - return false -} -``` - -## C++ - -```cpp -class Solution { -public: - bool repeatedSubstringPattern(string s) { - int n = s.length(); - - for (int i = 1; i <= n / 2; i++) { - if (n % i != 0) { - continue; - } - - string pattern = s.substr(0, i); - string repeated = ""; - - for (int j = 0; j < n / i; j++) { - repeated += pattern; - } - - if (repeated == s) { - return true; - } - } - - return false; - } -}; -``` - -## Java - -```java -class Solution { - public boolean repeatedSubstringPattern(String s) { - int n = s.length(); - - for (var i = 1; i <= n / 2; i++) { - if (n % i != 0) { - continue; - } - - var pattern = s.substring(0, i); - var repeated = new StringBuilder(); - - // Simply concatenate the pattern multiple times - for (var j = 0; j < n / i; j++) { - repeated.append(pattern); - } - - // Compare the constructed string with the original string - if (repeated.toString().equals(s)) { - return true; - } - } - - return false; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public bool RepeatedSubstringPattern(string s) - { - int n = s.Length; - - for (int i = 1; i <= n / 2; i++) - { - if (n % i != 0) - { - continue; - } - - // Get the potential substring pattern - string pattern = s.Substring(0, i); - StringBuilder repeated = new StringBuilder(); - - // Simply concatenate the pattern multiple times - for (int j = 0; j < n / i; j++) - { - repeated.Append(pattern); - } - - // Compare the constructed string with the original string - if (repeated.ToString() == s) - { - return true; - } - } - - return false; - } -} -``` - -## Ruby - -```ruby -# @param {String} s -# @return {Boolean} -def repeated_substring_pattern(s) - n = s.length - - (1..n / 2).each do |i| - next unless n % i == 0 - - pattern = s[0...i] - repeated = "" - - # Simply concatenate the pattern multiple times - (0...(n / i)).each do - repeated += pattern - end - - # Compare the constructed string with the original string - return true if repeated == s - end - - false -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[459. 重复的子字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/459-repeated-substring-pattern). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/463-island-perimeter.md b/zh/1-1000/463-island-perimeter.md deleted file mode 100644 index dde4d77..0000000 --- a/zh/1-1000/463-island-perimeter.md +++ /dev/null @@ -1,215 +0,0 @@ -# LeetCode 463. Island Perimeter's Solution -LeetCode link: [463. Island Perimeter](https://leetcode.com/problems/island-perimeter) - -## LeetCode problem description -You are given `row x col` `grid` representing a map where `grid[i][j] = 1` represents land and `grid[i][j] = 0` represents water. - -Grid cells are connected **horizontally/vertically** (not diagonally). The `grid` is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells). - -The island doesn't have "lakes", meaning the water inside isn't connected to the water around the island. One cell is a square with side length 1. The grid is rectangular, width and height don't exceed 100. Determine the perimeter of the island. - -### Example 1 -![](../../images/examples/463_1.png) -``` -Input: grid = [ - [0,1,0,0], - [1,1,1,0], - [0,1,0,0], - [1,1,0,0] -] -Output: 16 -Explanation: The perimeter is the 16 yellow stripes in the image above. -``` - -### Example 2 -``` -Input: grid = [[1]] -Output: 4 -``` - -### Example 3 -``` -Input: grid = [[1,0]] -Output: 4 -``` - -### Constraints -- `row == grid.length` -- `col == grid[i].length` -- `1 <= row, col <= 100` -- `grid[i][j]` is `0` or `1`. -- There is exactly one island in `grid`. - -## Intuition and Approach 1: Straightforward -1. To calculate the perimeter of an island, we simply add up the number of water-adjacent edges of all water-adjacent lands. -2. When traversing the grid, once land is found, the number of its adjacent water edges is calculated. - -## Intuition 2 -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph has only one **connected components** (island). - -## Approach 2: Depth-First Search the Island (complex way) -1. Find the first land. -1. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Depth-First Search** (DFS) and **Breadth-First Search** (BFS). - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. Here I will provide the `Recursive` solution. - * If you want to know **Depth-First Search** `Iterative` solution, please see [200. Number of Islands (Depth-First Search by Iteration)](200-number-of-islands-2.md). - * If you want to know **Breadth-First Search** solution, please see [200. Number of Islands (Breadth-First Search)](200-number-of-islands-3.md). - * Mark each found land as `8` which represents `visited`. Visited lands don't need to be visited again. -1. To calculate the perimeter of an island, we simply add up the number of water-adjacent edges of all water-adjacent lands. -1. To solve this problem, you don't really need to use `DFS` or `BFS`, but mastering `DFS` and `BFS` is absolutely necessary. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(1)`. - -## Python -### Solution 1: Straightforward -```python -class Solution: - def __init__(self): - self.grid = None - - def islandPerimeter(self, grid: List[List[int]]) -> int: - self.grid = grid - perimeter = 0 - - for i in range(len(grid)): - for j in range(len(grid[0])): - if grid[i][j] == 1: - perimeter += self.water_side_count(i, j) - - return perimeter - - def water_side_count(self, i, j): - side_count = 0 - - for a, b in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0), - ]: - m = i + a - n = j + b - - if m < 0 or n < 0 or m >= len(self.grid) or n >= len(self.grid[0]) \ - or self.grid[m][n] == 0: - side_count += 1 - - return side_count -``` - -### Solution 2: Depth-First Search the Island (complex way) -```python -class Solution: - def __init__(self): - self.perimeter = 0 - self.grid = None - - def islandPerimeter(self, grid: List[List[int]]) -> int: - self.grid = grid - - for i, row in enumerate(self.grid): - for j, value in enumerate(row): - if value == 1: - self.depth_first_search(i, j) - - return self.perimeter - - def depth_first_search(self, i, j): - if i < 0 or i >= len(self.grid): - return - - if j < 0 or j >= len(self.grid[0]): - return - - if self.grid[i][j] != 1: - return - - self.grid[i][j] = 8 - - self.perimeter += self.water_edges(i, j) - - self.depth_first_search(i - 1, j) - self.depth_first_search(i, j + 1) - self.depth_first_search(i + 1, j) - self.depth_first_search(i, j - 1) - - def water_edges(self, i, j): - result = 0 - result += self.water_edge(i - 1, j) - result += self.water_edge(i, j + 1) - result += self.water_edge(i + 1, j) - result += self.water_edge(i, j - 1) - return result - - def water_edge(self, i, j): - if i < 0 or i >= len(self.grid): - return 1 - - if j < 0 or j >= len(self.grid[0]): - return 1 - - if self.grid[i][j] == 0: - return 1 - - return 0 -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/474-ones-and-zeroes.md b/zh/1-1000/474-ones-and-zeroes.md deleted file mode 100644 index 7203d15..0000000 --- a/zh/1-1000/474-ones-and-zeroes.md +++ /dev/null @@ -1,473 +0,0 @@ -# 474. 一和零 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[474. 一和零 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/474-ones-and-zeroes),体验更佳! - -力扣链接:[474. 一和零](https://leetcode.cn/problems/ones-and-zeroes), 难度等级:**中等**。 - -## LeetCode “474. 一和零”问题描述 - -给你一个二进制字符串数组 `strs` 和两个整数 `m` 和 `n` 。 - -请你找出并返回 `strs` 的最大子集的长度,该子集中 **最多** 有 `m` 个 `0` 和 `n` 个 `1` 。 - -如果 `x` 的所有元素也是 `y` 的元素,集合 `x` 是集合 `y` 的 **子集** 。 - -### [示例 1] - -**输入**: `strs = ["10","0001","111001","1","0"], m = 5, n = 3` - -**输出**: `4` - -**解释**: - -

最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
-其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

- - -### [示例 2] - -**输入**: `strs = ["10","0","1"], m = 1, n = 1` - -**输出**: `2` - -**解释**: `最大的子集是 {"0", "1"} ,所以答案是 2 。` - -### [约束] - -- `1 <= strs.length <= 600` -- `1 <= strs[i].length <= 100` -- `'strs[i]' consists only of digits '0' and '1'` -- `1 <= m, n <= 100` - -## 思路 - -本题偏难,建议先完成一个同类的简单题目[416. 分割等和子集](416-partition-equal-subset-sum.md)。 - -- 在完成了416后,你会发现本题要在两个维度上解决`0/1问题`。 -- 解决方法是先在一维上解决问题,然后再将其扩展到二维。 -- 没有必要画一个同时考虑两个维度的网格,那太复杂了。我们可以先**只**考虑`0`的数量限制。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## “0/1背包问题”的模式 - -典型的“0/1背包问题”,指每个“物品”只能使用一次,来填充“背包”。“物品”有“重量”和“价值”属性,求“背包”能存放的“物品”的最大价值。 - -其特点是:有**一组数字**,每个数字只能被使用一次,通过某种计算得到**另一个数字**。问题也可以变成能否得到?有多少种变化?等。 - -因为“0/1背包问题”属于“动态规划”,所以我会用“动态规划”的模式讲解。 - -1. 确定数组`dp`的每个值代表的含义。 - - 首选**一维滚动数组**,代码简洁。 - - 确定什么是“物品”,什么是“背包”。 - - 如果`dp[j]`是一个布尔值,则`dp[j]`表示是否可以前`i`个`物品`的`和`得到`j`。 - - 如果`dp[j]`是一个数值,则`dp[j]`表示是利用前`i`个`物品`,`dp[j]`能达到的所求问题的极限值。 -2. 初始化数组`dp`的值。 - - 确定“背包”的大小。需要让背包大小再加1,即插入`dp[0]`做为起始点,方便理解和引用。 - - `dp[0]`有时需要特殊处理。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - 先在外层循环中,**遍历物品**。 - - 后在内层循环中,**遍历背包大小**。 - - 在遍历背包大小时,由于`dp[j]`取决于`dp[j]`和`dp[j - weights[i]]`,因此我们应该**从右到左**遍历`dp`数组。 - - 请思考是否可以从`从左到右`遍历`dp`数组? -4. 根据`dp`网格数据,推导出“递推公式”。 - - 如果`dp[j]`是一个布尔值: - - ```cpp - dp[j] = dp[j] || dp[j - weights[i]] - ``` - - 如果`dp[j]`是一个数值: - - ```cpp - dp[j] = min_or_max(dp[j], dp[j - weights[i]] + values[i]) - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 步骤 - -1. 确定`dp[j]`的**含义** - - 由于我们目前只考虑零计数约束,因此我们可以使用一维`dp`数组。 - - `物品`是`strs`,`背包`是`max_zero_count`。 - - `dp[j]`表示最多可以用`j`个零来选择的最大字符串数。 - - `dp[j]`是一个整数。 - -2. 确定`dp`数组的初始值 - - 使用一个例子,示例1:`输入:strs = ["10","0001","111001","1","0"],m = 5,n = 3`。 - - 初始化后: - - ```python - max_zero_count = m - dp = [0] * (max_zero_count + 1) - ``` - - `dp[0] = 0`,表示没有零,我们可以选择 0 个字符串。 - - `dp[j] = 0` 作为初始值,因为我们稍后将使用 `max` 来增加它们。 - -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - ``` - # Initial state - # 0 1 2 3 4 5 - # 0 0 0 0 0 0 - - # After processing "10" (1 zero) - # 0 1 2 3 4 5 - # 0 1 1 1 1 1 - - # After processing "0001" (3 zeros) - # 0 1 2 3 4 5 - # 0 1 1 1 2 2 - - # After processing "111001" (2 zeros) - # 0 1 2 3 4 5 - # 0 1 1 2 2 2 - - # After processing "1" (0 zeros) - # 0 1 2 3 4 5 - # 0 2 2 3 3 3 - - # After processing "0" (1 zero) - # 0 1 2 3 4 5 - # 0 2 3 3 4 4 - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```cpp - dp[j] = max(dp[j], dp[j - zero_count] + 1) - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -只考虑`0`数量限制的代码是: - -```python -class Solution: - def findMaxForm(self, strs: List[str], max_zero_count: int, n: int) -> int: - dp = [0] * (max_zero_count + 1) - - for string in strs: - zero_count = count_zero(string) - - for j in range(len(dp) - 1, zero_count - 1, -1): # must iterate in reverse order! - dp[j] = max(dp[j], dp[j - zero_count] + 1) - - return dp[-1] - - -def count_zero(string): - zero_count = 0 - - for bit in string: - if bit == '0': - zero_count += 1 - - return zero_count -``` - -#### 现在,你可以考虑另一个维度:`1`的数量限制。 - -它应该以与“0”类似的方式处理,只不过是在另一个维度上。请参阅下面的完整代码。 - -## 复杂度 - -- 时间复杂度: `O(N * M * Len)`. -- 空间复杂度: `O(N * M)`. - -## Python - -```python -class Solution: - def findMaxForm(self, strs: List[str], max_zero_count: int, max_one_count: int) -> int: - dp = [[0] * (max_one_count + 1) for _ in range(max_zero_count + 1)] - - for string in strs: - zero_count, one_count = count_zero_one(string) - - for i in range(len(dp) - 1, zero_count - 1, -1): - for j in range(len(dp[0]) - 1, one_count - 1, -1): - dp[i][j] = max(dp[i][j], dp[i - zero_count][j - one_count] + 1) - - return dp[-1][-1] - - -def count_zero_one(string): - zero_count = 0 - one_count = 0 - - for bit in string: - if bit == '0': - zero_count += 1 - else: - one_count += 1 - - return zero_count, one_count -``` - -## C++ - -```cpp -class Solution { -public: - int findMaxForm(vector& strs, int max_zero_count, int max_one_count) { - vector> dp(max_zero_count + 1, vector(max_one_count + 1, 0)); - - for (auto& str : strs) { - auto zero_count = 0; - auto one_count = 0; - - for (auto bit : str) { - if (bit == '0') { - zero_count++; - } else { - one_count++; - } - } - - for (auto i = max_zero_count; i >= zero_count; i--) { - for (auto j = max_one_count; j >= one_count; j--) { - dp[i][j] = max(dp[i][j], dp[i - zero_count][j - one_count] + 1); - } - } - } - - return dp[max_zero_count][max_one_count]; - } -}; -``` - -## Java - -```java -class Solution { - public int findMaxForm(String[] strs, int maxZeroCount, int maxOneCount) { - var dp = new int[maxZeroCount + 1][maxOneCount + 1]; - - for (var str : strs) { - var zeroCount = 0; - var oneCount = 0; - - for (var bit : str.toCharArray()) { - if (bit == '0') { - zeroCount++; - } else { - oneCount++; - } - } - - for (var i = maxZeroCount; i >= zeroCount; i--) { - for (var j = maxOneCount; j >= oneCount; j--) { - dp[i][j] = Math.max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1); - } - } - } - - return dp[maxZeroCount][maxOneCount]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public int FindMaxForm(string[] strs, int maxZeroCount, int maxOneCount) - { - var dp = new int[maxZeroCount + 1, maxOneCount + 1]; - - foreach (var str in strs) - { - var (zeroCount, oneCount) = CountZeroOne(str); - - for (var i = maxZeroCount; i >= zeroCount; i--) - { - for (var j = maxOneCount; j >= oneCount; j--) - { - dp[i, j] = Math.Max(dp[i, j], dp[i - zeroCount, j - oneCount] + 1); - } - } - } - - return dp[maxZeroCount, maxOneCount]; - } - - (int, int) CountZeroOne(string str) - { - var zeroCount = 0; - var oneCount = 0; - - foreach (var bit in str) - { - if (bit == '0') - { - zeroCount++; - } - else - { - oneCount++; - } - } - - return (zeroCount, oneCount); - } -} -``` - -## JavaScript - -```javascript -var findMaxForm = function (strs, maxZeroCount, maxOneCount) { - const dp = Array(maxZeroCount + 1).fill().map( - () => Array(maxOneCount + 1).fill(0) - ) - - for (const str of strs) { - const [zeroCount, oneCount] = countZeroOne(str) - - for (let i = dp.length - 1; i >= zeroCount; i--) { - for (let j = dp[0].length - 1; j >= oneCount; j--) { - dp[i][j] = Math.max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1) - } - } - } - - return dp.at(-1).at(-1) -}; - -function countZeroOne(str) { - let zeroCount = 0 - let oneCount = 0 - - for (const bit of str) { - if (bit === '0') { - zeroCount++ - } else { - oneCount++ - } - } - - return [zeroCount, oneCount] -} -``` - -## Go - -```go -func findMaxForm(strs []string, maxZeroCount int, maxOneCount int) int { - dp := make([][]int, maxZeroCount + 1) - for i := range dp { - dp[i] = make([]int, maxOneCount + 1) - } - - for _, str := range strs { - zeroCount, oneCount := countZeroOne(str) - - for i := len(dp) - 1; i >= zeroCount; i-- { - for j := len(dp[0]) - 1; j >= oneCount; j-- { - dp[i][j] = max(dp[i][j], dp[i - zeroCount][j - oneCount] + 1) - } - } - } - - return dp[maxZeroCount][maxOneCount] -} - -func countZeroOne(str string) (int, int) { - zeroCount := 0 - oneCount := 0 - - for _, bit := range str { - if bit == '0' { - zeroCount++ - } else { - oneCount++ - } - } - - return zeroCount, oneCount -} -``` - -## Ruby - -```ruby -def find_max_form(strs, max_zero_count, max_one_count) - dp = Array.new(max_zero_count + 1) do - Array.new(max_one_count + 1, 0) - end - - strs.each do |string| - zero_count, one_count = count_zero_one(string) - - (zero_count...dp.size).reverse_each do |i| - (one_count...dp[0].size).reverse_each do |j| - dp[i][j] = [ dp[i][j], dp[i - zero_count][j - one_count] + 1 ].max - end - end - end - - dp[-1][-1] -end - -def count_zero_one(string) - zero_count = 0 - one_count = 0 - - string.each_char do |bit| - if bit == '0' - zero_count += 1 - else - one_count += 1 - end - end - - [ zero_count, one_count ] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[474. 一和零 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/474-ones-and-zeroes). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/49-group-anagrams.md b/zh/1-1000/49-group-anagrams.md deleted file mode 100644 index f496d2a..0000000 --- a/zh/1-1000/49-group-anagrams.md +++ /dev/null @@ -1,111 +0,0 @@ -# 49. 字母异位词分组 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[49. 字母异位词分组 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/49-group-anagrams),体验更佳! - -力扣链接:[49. 字母异位词分组](https://leetcode.cn/problems/group-anagrams), 难度等级:**中等**。 - -## LeetCode “49. 字母异位词分组”问题描述 - -给你一个字符串数组,请你将 **字母异位词** 组合在一起。可以按任意顺序返回结果列表。 - -> **字母异位词** 是由重新排列源单词的所有字母得到的一个新单词。 - -### [示例 1] - -**输入**: `strs = ["eat", "tea", "tan", "ate", "nat", "bat"]` - -**输出**: `[["bat"],["nat","tan"],["ate","eat","tea"]]` - -### [示例 2] - -**输入**: `strs = [""]` - -**输出**: `[[""]]` - -### [示例 3] - -**输入**: `strs = ["a"]` - -**输出**: `[["a"]]` - -### [约束] - -- `1 <= strs.length <= 10^4` -- `0 <= strs[i].length <= 100` -- `strs[i]` 仅包含小写字母 - -## 思路 - -- 两个字符串,`bat`和`atb`,用什么方法能最快地知道他们是字母异位词呢? - -
点击查看答案

将每个字符串都按字母表顺序排序,然后比较排过序的两个字符串。相等,就是。

- -- 但是排序后,原字符串没有被考虑进来,而结果求的是原字符串的分组。如何解决? - -
点击查看答案

用元组,即把按字母表顺序排序后的字符串和原字符串放在一个元组里,像这样:`("abt", "bat")`。

- -- 剩下要做的,就是对这个元组数组进行分组了。如何分组最简单? - -
点击查看答案

用`Map`,`key`是按字母表顺序排过序的字符串,`value`是原字符串的数组。

- -## 复杂度 - -> M = string.length - -- 时间复杂度: `O(N * M * logM)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def groupAnagrams(self, strs: List[str]) -> List[List[str]]: - pairs = [(''.join(sorted(string)), string) for string in strs] - - ordered_to_original = defaultdict(list) - - for ordered, original in pairs: - ordered_to_original[ordered].append(original) - - return list(ordered_to_original.values()) -``` - -## Ruby - -```ruby -# @param {String[]} strs -# @return {String[][]} -def group_anagrams(strs) - pairs = strs.map { |string| [ string.chars.sort.join, string ] } - - ordered_to_original = Hash.new([]) - - pairs.each do |ordered, original| - ordered_to_original[ordered] += [original] - end - - ordered_to_original.values -end - -# Or solution 2: More concise way - -# @param {String[]} strs -# @return {String[][]} -def group_anagrams(strs) - strs.group_by { |string| string.chars.sort }.values -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[49. 字母异位词分组 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/49-group-anagrams). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/494-target-sum.md b/zh/1-1000/494-target-sum.md deleted file mode 100644 index 105fdbc..0000000 --- a/zh/1-1000/494-target-sum.md +++ /dev/null @@ -1,342 +0,0 @@ -# 494. 目标和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[494. 目标和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/494-target-sum),体验更佳! - -力扣链接:[494. 目标和](https://leetcode.cn/problems/target-sum), 难度等级:**中等**。 - -## LeetCode “494. 目标和”问题描述 - -给你一个非负整数数组 `nums` 和一个整数 `target` 。 - -向数组中的每个整数前添加 `'+'` 或 `'-'` ,然后串联起所有整数,可以构造一个 **表达式** : - -- 例如,`nums = [2, 1]` ,可以在 `2` 之前添加 `'+'` ,在 `1` 之前添加 `'-'` ,然后串联起来得到表达式 `"+2-1"` 。 - -返回可以通过上述方法构造的、运算结果等于 `target` 的不同 **表达式** 的数目。 - -### [示例 1] - -**输入**: `nums = [1,1,1,1,1], target = 3` - -**输出**: `5` - -**解释**: - -

-1 + 1 + 1 + 1 + 1 = 3
-+1 - 1 + 1 + 1 + 1 = 3
-+1 + 1 - 1 + 1 + 1 = 3
-+1 + 1 + 1 - 1 + 1 = 3
-+1 + 1 + 1 + 1 - 1 = 3

- - -### [示例 2] - -**输入**: `nums = [1], target = 1` - -**输出**: `1` - -### [约束] - -- `1 <= nums.length <= 20` -- `0 <= nums[i] <= 1000` -- `0 <= sum(nums[i]) <= 1000` -- `-1000 <= target <= 1000` - -## 思路 - -如果你以前没有解决过类似的问题,那么这个问题相当难。所以在开始做这道题之前,建议你先做另一道与这道题类似的相对简单的题目[416. 分割相等子集和](416-partition-equal-subset-sum.md)。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 步骤 - -1. 确定`dp[j]`的**含义** - - `dp[j]`表示通过使用**前**个`i`个数字,您可以构建的不同**表达式**的数量,其计算结果为`j`。 - - `dp[j]`是一个**整数**。 -2. 确定`dp`数组的初始值 - - 使用一个例子。我们没有使用`示例1:输入:nums = [1,1,1,1,1], target = 3`,因为它太特殊,不是推导公式的好例子。 - - 我编了一个例子:`nums = [1,2,1,2], target = 4`。 - - 首先,确定背包的`size`。 - - `target`值可能很小,比如`0`,所以光靠它不能确定背包的`size`。 - - 还应该考虑`nums`的总和,以完全覆盖所有背包尺寸。 - - `target`可以是负数,但考虑到`+`和`-`是任意添加到`num`的,`dp[j]`应该围绕`0`对称。所以负数 `target` 的结果 `dp[target]` 等于 `dp[abs(target)]`。 - - 所以背包的 `size` 可以是 `max(sum(nums), target) + 1`。 - - 然后,确定什么是`物品`。`物品`在本题中 就是 `nums`。 - - ``` - 所以初始化后,`dp` 数组将是: - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 # dp - # 1 - # 2 - # 1 - # 2 - ``` - - `dp[0]` 设置为 `1`,表示不使用任何 `nums` 就可以实现空背包。另外,它作为起始值,后面的`dp[j]`都会依赖它,如果为`0`,则`dp[j]`的所有值都为`0`。 - - `dp[j] = 0 (j != 0)`,说明没有`nums`是不可能得到`j`的。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - ``` - 1. 使用第一个数字'1'。 - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 # dp - # 2 - # 1 - # 2 - ``` - ``` - 2. 使用第二个数字'2'。 - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 - # 2 0 1 0 1 0 0 0 - # 1 - # 2 - ``` - ``` - 3. 使用第三个数字'1'。 - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 - # 2 0 1 0 1 0 0 0 - # 1 2 0 2 0 1 0 0 - # 2 - ``` - ``` - 4. 使用第四个数字'2'。 - # 0 1 2 3 4 5 6 - # 1 0 0 0 0 0 0 - # 1 0 1 0 0 0 0 0 - # 2 0 1 0 1 0 0 0 - # 1 2 0 2 0 1 0 0 - # 2 4 0 3 0 2 0 1 # dp - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```java - dp[j] = dp[abs(j - nums[i])] + dp[j + nums[i]] - ``` - - 如果 `j < nums[i]`,`dp[j - nums[i]]` 将引发 `数组索引超出范围` 异常。因此我们使用等于它的 `dp[abs(j - num)]`,因为 `dp[j]` 是围绕 `0` 对称的,比如 `dp[-j]` 等于 `dp[j]`(`-j` 是虚数索引)。 - - 当 `j + nums[i] >= dp.length`时,`dp[j + nums[i]]` 必须为 `0`,防止产生干扰。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 复杂度 - -- 时间复杂度: `O(n * sum)`. -- 空间复杂度: `O(n * sum)`. - -## C# - -```csharp -public class Solution -{ - public int FindTargetSumWays(int[] nums, int target) - { - target = Math.Abs(target); - - var dp = new int[Math.Max(nums.Sum(), target) + 1]; - dp[0] = 1; - - foreach (var num in nums) - { - var dc = (int[])dp.Clone(); - - for (var j = 0; j < dp.Length; j++) - { - dp[j] = dc[Math.Abs(j - num)] + (j + num < dp.Length ? dc[j + num] : 0); - } - } - - return dp[target]; - } -} -``` - -## Python - -```python -class Solution: - def findTargetSumWays(self, nums: List[int], target: int) -> int: - target = abs(target) - - dp = [0] * (max(sum(nums), target) + 1) - dp[0] = 1 - - for num in nums: - dc = dp.copy() - - for j in range(len(dp)): - dp[j] = dc[abs(j - num)] + (dc[j + num] if j + num < len(dp) else 0) - - return dp[target] -``` - -## C++ - -```cpp -class Solution { -public: - int findTargetSumWays(vector& nums, int target) { - auto sum = reduce(nums.begin(), nums.end()); - target = abs(target); - - auto dp = vector(max(sum, target) + 1); - dp[0] = 1; - - for (auto num : nums) { - auto dc = dp; - - for (auto j = 0; j < dp.size(); j++) { - dp[j] = dc[abs(j - num)] + (j + num < dp.size() ? dc[j + num] : 0); - } - } - - return dp[target]; - } -}; -``` - -## Java - -```java -class Solution { - public int findTargetSumWays(int[] nums, int target) { - var sum = IntStream.of(nums).sum(); - target = Math.abs(target); - - var dp = new int[Math.max(sum, target) + 1]; - dp[0] = 1; - - for (var num : nums) { - var dc = dp.clone(); - - for (var j = 0; j < dp.length; j++) { - dp[j] = dc[Math.abs(j - num)] + (j + num < dp.length ? dc[j + num] : 0); - } - } - - return dp[target]; - } -} -``` - -## JavaScript - -```javascript -var findTargetSumWays = function (nums, target) { - target = Math.abs(target) - - const dp = Array(Math.max(_.sum(nums), target) + 1).fill(0) - dp[0] = 1 - - for (const num of nums) { - const dc = [...dp] - - for (let j = 0; j < dp.length; j++) { - dp[j] = dc[Math.abs(j - num)] + (j + num < dp.length ? dc[j + num] : 0) - } - } - - return dp[target] -}; -``` - -## Go - -```go -func findTargetSumWays(nums []int, target int) int { - sum := 0 - for _, num := range nums { - sum += num - } - target = int(math.Abs(float64(target))) - - dp := make([]int, max(sum, target) + 1) - dp[0] = 1 - - for _, num := range nums { - dc := slices.Clone(dp) - - for j := 0; j < len(dp); j++ { - addition := 0 - if j + num < len(dp) { - addition = dc[j + num] - } - dp[j] = dc[int(math.Abs(float64((j - num))))] + addition - } - } - - return dp[target] -} -``` - -## Ruby - -```ruby -def find_target_sum_ways(nums, target) - target = target.abs - - dp = Array.new([ nums.sum, target ].max + 1, 0) - dp[0] = 1 - - nums.each do |num| - dc = dp.clone - - dp.each_with_index do |_, j| - dp[j] = dc[(j - num).abs] + (j + num < dp.size ? dc[j + num] : 0) - end - end - - dp[target] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[494. 目标和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/494-target-sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/496-next-greater-element-i.md b/zh/1-1000/496-next-greater-element-i.md deleted file mode 100644 index a74e834..0000000 --- a/zh/1-1000/496-next-greater-element-i.md +++ /dev/null @@ -1,415 +0,0 @@ -# 496. Next Greater Element I -LeetCode link: [496. Next Greater Element I](https://leetcode.com/problems/next-greater-element-i/) - -## LeetCode problem description -The next greater element of some element `x` in an array is the first greater element that is to the right of `x` in the same array. - -You are given two distinct 0-indexed integer arrays `nums1` and `nums2`, where `nums1` is a subset of `nums2`. - -For each `0 <= i < nums1.length`, find the index `j` such that `nums1[i] == nums2[j]` and determine the next greater element of `nums2[j]` in `nums2`. If there is no next greater element, then the answer for this query is `-1`. - -Return an array `ans` of length `nums1.length` such that `ans[i]` is the next greater element as described above. - -``` ------------------------------------------------------------------------------------------------ -[Example 1] - -Input: nums1 = [4,1,2], nums2 = [1,3,4,2] -Output: [-1,3,-1] - -Explanation: The next greater element for each value of nums1 is as follows: -- 4 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. -- 1 is underlined in nums2 = [1,3,4,2]. The next greater element is 3. -- 2 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. ------------------------------------------------------------------------------------------------ -[Example 2] - -Input: nums1 = [2,4], nums2 = [1,2,3,4] -Output: [3,-1] - -Explanation: The next greater element for each value of nums1 is as follows: -- 2 is underlined in nums2 = [1,2,3,4]. The next greater element is 3. -- 4 is underlined in nums2 = [1,2,3,4]. There is no next greater element, so the answer is -1. ------------------------------------------------------------------------------------------------ -[Constraints] - -1 <= nums1.length <= nums2.length <= 1000 -0 <= nums1[i], nums2[i] <= 10000 -All integers in 'nums1' and 'nums2' are unique. -All the integers of 'nums1' also appear in 'nums2'. ------------------------------------------------------------------------------------------------ -``` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -#### Brute force solution -* Time: `O(n * m)`. -* Space: `O(n)`. - -#### Monotonic stack solution -* Time: `O(n + m)`. -* Space: `O(n)`. - -## Java -### Brute force solution -```java -class Solution { - public int[] nextGreaterElement(int[] nums1, int[] nums2) { - var results = new int[nums1.length]; - Arrays.fill(results, -1); - - for (var i = 0; i < nums1.length; i++) { - var found = false; - - for (var num2 : nums2) { - if (found && num2 > nums1[i]) { - results[i] = num2; - break; - } - - if (nums1[i] == num2) { - found = true; - } - } - } - - return results; - } -} -``` - -### Monotonic stack solution -```java -class Solution { - public int[] nextGreaterElement(int[] nums1, int[] nums2) { - var numToGreaterNum = new HashMap(); - var stack = new Stack(); - - for (var num : nums2) { - while (!stack.empty() && stack.peek() < num) { - numToGreaterNum.put(stack.pop(), num); - } - - stack.push(num); - } - - var result = new int[nums1.length]; - - for (var i = 0; i < nums1.length; i++) { - result[i] = numToGreaterNum.getOrDefault(nums1[i], -1); - } - - return result; - } -} -``` - -## Python -### Brute force solution -```python -class Solution: - def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]: - results = [-1] * len(nums1) - - for i, num1 in enumerate(nums1): - found = False - - for num2 in nums2: - if found and num2 > num1: - results[i] = num2 - break - - if num1 == num2: - found = True - - return results -``` - -### Monotonic stack solution -```python -class Solution: - def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]: - num_to_greater_num = defaultdict(int) - stack = [] - - for num in nums2: - while stack and num > stack[-1]: - num_to_greater_num[stack.pop()] = num - - stack.append(num) - - return [num_to_greater_num[num] or -1 for num in nums1] -``` - -## C++ -### Brute force solution -```cpp -class Solution { -public: - vector nextGreaterElement(vector& nums1, vector& nums2) { - vector results(nums1.size(), -1); - - for (auto i = 0; i < nums1.size(); i++) { - auto found = false; - - for (auto num2 : nums2) { - if (found && num2 > nums1[i]) { - results[i] = num2; - break; - } - - if (nums1[i] == num2) { - found = true; - } - } - } - - return results; - } -}; -``` - -### Monotonic stack solution -```cpp -class Solution { -public: - vector nextGreaterElement(vector& nums1, vector& nums2) { - unordered_map num_to_greater_num; - stack monotonic_stack; - - for (auto num : nums2) { - while (!monotonic_stack.empty() && monotonic_stack.top() < num) { - num_to_greater_num[monotonic_stack.top()] = num; - monotonic_stack.pop(); - } - - monotonic_stack.push(num); - } - - vector result; - - for (auto num : nums1) { - result.emplace_back( - num_to_greater_num.contains(num) ? num_to_greater_num[num] : -1 - ); - } - - return result; - } -}; -``` - -## JavaScript -### Brute force solution -```javascript -var nextGreaterElement = function (nums1, nums2) { - const results = Array(nums1.length).fill(-1) - - nums1.forEach((num1, i) => { - let found = false - - for (const num2 of nums2) { - if (found && num2 > num1) { - results[i] = num2 - break - } - - if (num1 == num2) { - found = true - } - } - }) - - return results -}; -``` - -### Monotonic stack solution -```javascript -var nextGreaterElement = function (nums1, nums2) { - const numToGreaterNum = {} - const stack = [] - - nums2.forEach((num) => { - while (stack.length > 0 && stack.at(-1) < num) { - numToGreaterNum[stack.pop()] = num - } - - stack.push(num) - }) - - return nums1.map((num) => numToGreaterNum[num] || -1) -}; -``` - -## C# -### Brute force solution -```c# -public class Solution -{ - public int[] NextGreaterElement(int[] nums1, int[] nums2) - { - var results = new int[nums1.Length]; - Array.Fill(results, -1); - - for (var i = 0; i < nums1.Length; i++) - { - bool found = false; - - foreach (var num2 in nums2) - { - if (found && num2 > nums1[i]) - { - results[i] = num2; - break; - } - - if (nums1[i] == num2) - { - found = true; - } - } - } - - return results; - } -} -``` - -### Monotonic stack solution -```c# -public class Solution -{ - public int[] NextGreaterElement(int[] nums1, int[] nums2) - { - var numToGreater = new Dictionary(); - var stack = new Stack(); - - foreach (int num in nums2) - { - while (stack.Count > 0 && stack.Peek() < num) - { - numToGreater[stack.Pop()] = num; - } - - stack.Push(num); - } - - var result = new int[nums1.Length]; - - for (var i = 0; i < nums1.Length; i++) - { - result[i] = numToGreater.GetValueOrDefault(nums1[i], -1); - } - - return result; - } -} -``` - -## Go -### Brute force solution -```go -func nextGreaterElement(nums1 []int, nums2 []int) []int { - results := slices.Repeat([]int{-1}, len(nums1)) - - for i, num1 := range nums1 { - found := false - - for _, num2 := range nums2 { - if found && num2 > num1 { - results[i] = num2 - break - } - - if num1 == num2 { - found = true - } - } - } - - return results -} -``` - -### Monotonic stack solution -```go -func nextGreaterElement(nums1 []int, nums2 []int) []int { - numToGreaterNum := map[int]int{} - stack := []int{} - - for _, num := range nums2 { - for (len(stack) > 0 && stack[len(stack) - 1] < num) { - numToGreaterNum[stack[len(stack) - 1]] = num - stack = stack[:len(stack) - 1] - } - - stack = append(stack, num) - } - - results := slices.Repeat([]int{-1}, len(nums1)) - - for i, num1 := range nums1 { - if value, ok := numToGreaterNum[num1]; ok { - results[i] = value - } - } - - return results -} -``` - -## Ruby -### Brute force solution -```ruby -def next_greater_element(nums1, nums2) - results = Array.new(nums1.size, -1) - - nums1.each_with_index do |num1, i| - found = false - - nums2.each do |num2| - if found and num2 > num1 - results[i] = num2 - break - end - - found = true if num1 == num2 - end - end - - results -end -``` - -### Monotonic stack solution -```ruby -def next_greater_element(nums1, nums2) - num_to_greater_num = {} - stack = [] - - nums2.each do |num| - while !stack.empty? && stack.last < num - num_to_greater_num[stack.pop] = num - end - - stack << num - end - - nums1.map { |num| num_to_greater_num[num] || -1 } -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/5-longest-palindromic-substring.md b/zh/1-1000/5-longest-palindromic-substring.md deleted file mode 100644 index 4cd6342..0000000 --- a/zh/1-1000/5-longest-palindromic-substring.md +++ /dev/null @@ -1,149 +0,0 @@ -# 5. 最长回文子串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[5. 最长回文子串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/5-longest-palindromic-substring),体验更佳! - -力扣链接:[5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring), 难度等级:**中等**。 - -## LeetCode “5. 最长回文子串”问题描述 - -给你一个字符串 `s`,找到 `s` 中最长的 **回文子串**。 - -- **回文性**:如果字符串向前和向后读都相同,则它满足 **回文性**。 -- **子字符串** 是字符串中连续的 **非空** 字符序列。 - -### [示例 1] - -**输入**: `s = "babad"` - -**输出**: `"bab"` - -**解释**: `"aba" 同样是符合题意的答案。` - -### [示例 2] - -**输入**: `s = "cbbd"` - -**输出**: `"bb"` - -### [约束] - -- `1 <= s.length <= 1000` -- `s` 仅由数字和英文字母组成 - -### [Hints] - -
- 提示 1 - How can we reuse a previously computed palindrome to compute a larger palindrome? - - -
- -
- 提示 2 - If “aba” is a palindrome, is “xabax” a palindrome? Similarly is “xabay” a palindrome? - - -
- -
- 提示 3 - Complexity based hint: -If we use brute-force and check whether for every start and end position a substring is a palindrome we have O(n^2) start - end pairs and O(n) palindromic checks. Can we reduce the time for palindromic checks to O(1) by reusing some previous computation. - - -
- -## 思路 - - - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 复杂度 - -- 时间复杂度: ``. -- 空间复杂度: ``. - -## Ruby - -```ruby -# @param {String} s -# @return {String} -def longest_palindrome(s) - longest = s[0] - s = s.chars.join("#") - - s.size.times do |i| - j = 1 - - while j <= i and i + j < s.size - break if s[i - j] != s[i + j] - - if s[i - j] == '#' - j += 1 - next - end - - length = j * 2 + 1 - - if length > longest.size - longest = s[i - j..i + j] - end - - j += 1 - end - end - - longest.gsub('#', '') -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[5. 最长回文子串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/5-longest-palindromic-substring). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/503-next-greater-element-ii.md b/zh/1-1000/503-next-greater-element-ii.md deleted file mode 100644 index 2747f86..0000000 --- a/zh/1-1000/503-next-greater-element-ii.md +++ /dev/null @@ -1,224 +0,0 @@ -# 503. Next Greater Element II -LeetCode link: [503. Next Greater Element II](https://leetcode.com/problems/next-greater-element-ii/) - -## LeetCode problem description -Given a circular integer array `nums` (i.e., the next element of `nums[nums.length - 1]` is `nums[0]`), return the **next greater number** for every element in `nums`. - -The **next greater number** of a number `x` is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, return `-1` for this number. -``` ------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [1,2,1] -Output: [2,-1,2] - -Explanation: The first 1's next greater number is 2; -The number 2 can't find next greater number. -The second 1's next greater number needs to search circularly, which is also 2. ------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [1,2,3,4,3] -Output: [2,3,4,-1,4] ------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 10000 --10^9 <= nums[i] <= 10^9 ------------------------------------------------------------------------------------- -``` - -## Solution 1 -This problem can be solved using **Brute Force**. But if the `nums.length` is much greater, the solution will time out. -Then We need to use a more efficient algorithm. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * n)`. -* Space: `O(n)`. - -## Solution 2: More efficient algorithm via "Monotonic Stack" -This solution will reduce the time complexity to **O(n)**. - -A similar issue is [Next Greater Element I](496-next-greater-element-i.md). -You can read it first, then checkout the `Python` section for the code. - -## C# -```c# -public class Solution -{ - public int[] NextGreaterElements(int[] nums) - { - int[] nums2 = [..nums, ..nums]; - var results = new int[nums.Length]; - Array.Fill(results, -1); - - for (var i = 0; i < nums.Length; i++) - { - for (var j = i + 1; j < nums2.Length; j++) - { - if (nums2[j] > nums[i]) - { - results[i] = nums2[j]; - break; - } - } - } - - return results; - } -} -``` - -## Python -### Solution 1: Brute Force -```python -class Solution: - def nextGreaterElements(self, nums: List[int]) -> List[int]: - results = [-1] * len(nums) - nums2 = nums + nums - - for i, num1 in enumerate(nums): - for j in range(i + 1, len(nums2)): - if nums2[j] > num1: - results[i] = nums2[j] - break - - return results -``` - -### Solution 2: Monotonic Stack -```python -# This is a better test case: -# [2, 5, 3, 2, 4, 1] for `nums` -# [2, 5, 3, 2, 4, 1, 2, 5, 3, 2, 4] for `extended_nums` - -class Solution: - def nextGreaterElements(self, nums: List[int]) -> List[int]: - extended_nums = nums + nums[:-1] - index_stack = [] - result = [-1] * len(extended_nums) - - for i, num in enumerate(extended_nums): - while index_stack and extended_nums[index_stack[-1]] < num: - result[index_stack.pop()] = num - - index_stack.append(i) - - return result[:len(nums)] -``` - -## Java -```java -class Solution { - public int[] nextGreaterElements(int[] nums) { - var results = new int[nums.length]; - Arrays.fill(results, -1); - - var nums2 = Arrays.copyOf(nums, nums.length * 2); - System.arraycopy(nums, 0, nums2, nums.length, nums.length); - - for (var i = 0; i < nums.length; i++) { - for (var j = i + 1; j < nums2.length; j++) { - if (nums2[j] > nums[i]) { - results[i] = nums2[j]; - break; - } - } - } - - return results; - } -} -``` - -## C++ -```cpp -class Solution { -public: - vector nextGreaterElements(vector& nums) { - vector results(nums.size(), -1); - auto nums2 = nums; - ranges::copy(nums, back_inserter(nums2)); - - for (auto i = 0; i < nums.size(); i++) { - for (auto j = i + 1; j < nums2.size(); j++) { - if (nums2[j] > nums[i]) { - results[i] = nums2[j]; - break; - } - } - } - - return results; - } -}; -``` - -## JavaScript -```javascript -var nextGreaterElements = function (nums) { - const results = Array(nums.length).fill(-1) - const nums2 = [...nums, ...nums] - - for (let i = 0; i < nums.length; i++) { - for (let j = i + 1; j < nums2.length; j++) { - if (nums2[j] > nums[i]) { - results[i] = nums2[j] - break - } - } - } - - return results -}; -``` - -## Go -```go -func nextGreaterElements(nums []int) []int { - results := slices.Repeat([]int{-1}, len(nums)) - nums2 := slices.Repeat(nums, 2) - - for i, num := range nums { - for j := i + 1; j < len(nums2); j++ { - if nums2[j] > num { - results[i] = nums2[j] - break - } - } - } - - return results -} -``` - -## Ruby -```ruby -def next_greater_elements(nums) - results = Array.new(nums.size, -1) - nums2 = nums + nums - - nums.each_with_index do |num, i| - ((i + 1)...nums2.size).each do |j| - if nums2[j] > num - results[i] = nums2[j] - break - end - end - end - - results -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/509-fibonacci-number.md b/zh/1-1000/509-fibonacci-number.md deleted file mode 100644 index 1ddab6a..0000000 --- a/zh/1-1000/509-fibonacci-number.md +++ /dev/null @@ -1,612 +0,0 @@ -# 509. 斐波那契数 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[509. 斐波那契数 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/509-fibonacci-number),体验更佳! - -力扣链接:[509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number), 难度等级:**简单**。 - -## LeetCode “509. 斐波那契数”问题描述 - -**斐波那契数** (通常用 `F(n)` 表示)形成的序列称为 **斐波那契数列** 。该数列由 `0` 和 `1` 开始,后面的每一项数字都是前面两项数字的和。也就是: - -> F(0) = 0,F(1) = 1 -> F(n) = F(n - 1) + F(n - 2),其中 n > 1 - -给定 `n` ,请计算 `F(n)` 。 - -### [示例 1] - -**输入**: `n = 2` - -**输出**: `1` - -**解释**: `F(2) = F(1) + F(0) = 1 + 0 = 1` - -### [示例 2] - -**输入**: `n = 3` - -**输出**: `2` - -**解释**: `F(3) = F(2) + F(1) = 1 + 1 = 2` - -### [示例 3] - -**输入**: `n = 4` - -**输出**: `3` - -**解释**: `F(4) = F(3) + F(2) = 2 + 1 = 3` - -### [约束] - -0 <= n <= 30 - -## 思路 1 - - - -## “递归”的模式 - -递归(Recursion)是计算机科学和数学中的一个重要概念,指的是 一个函数在其定义中 **直接或间接调用自身** 的方法。 - -### 递归的核心思想 - -- **自我调用**:函数在执行过程中调用自身。 -- **基线情况**:相当于终止条件。到达基线情况后,就可以返回结果了,不需要再递归调用,防止无限循环。 -- **递归步骤**:问题逐步向“基线情况”靠近的步骤。 - -## 复杂度 - -> 如果不加用于缓存已知结果的Map,时间复杂度将上升为O( 2^N ) - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## C# - -```csharp -public class Solution { - IDictionary numToFibNum = new Dictionary(); - - public int Fib(int n) { - if (n <= 1) { - return n; - } - - if (numToFibNum.ContainsKey(n)) { - return numToFibNum[n]; - } - - numToFibNum[n] = Fib(n - 1) + Fib(n - 2); - - return numToFibNum[n]; - } -} -``` - -## Python - -```python -class Solution: - @cache - def fib(self, n: int) -> int: - if n <= 1: - return n - - return self.fib(n - 1) + self.fib(n - 2) -``` - -## C++ - -```cpp -class Solution { -public: - int fib(int n) { - if (n <= 1) { - return n; - } - - if (num_to_fib_num_.contains(n)) { - return num_to_fib_num_[n]; - } - - num_to_fib_num_[n] = fib(n - 1) + fib(n - 2); - - return num_to_fib_num_[n]; - } - -private: - unordered_map num_to_fib_num_; -}; -``` - -## Java - -```java -class Solution { - var numToFibNum = new HashMap(); - - public int fib(int n) { - if (n <= 1) { - return n; - } - - if (numToFibNum.containsKey(n)) { - return numToFibNum.get(n); - } - - numToFibNum.put(n, fib(n - 1) + fib(n - 2)); - - return numToFibNum.get(n); - } -} -``` - -## JavaScript - -```javascript -const numToFibNum = new Map() - -var fib = function (n) { - if (n <= 1) { - return n - } - - if (numToFibNum.has(n)) { - return numToFibNum.get(n) - } - - numToFibNum.set(n, fib(n - 1) + fib(n - 2)) - - return numToFibNum.get(n) -}; -``` - -## Go - -```go -func fib(m int) int { - numToFibNum := map[int]int{} - - var fibonacci func (int) int - - fibonacci = func (n int) int { - if n <= 1 { - return n - } - - if result, ok := numToFibNum[n]; ok { - return result - } - - numToFibNum[n] = fibonacci(n - 1) + fibonacci(n - 2) - return numToFibNum[n] - } - - return fibonacci(m) -} -``` - -## Ruby - -```ruby -def fib(n) - return n if n <= 1 - - @cache = {} if @cache.nil? - - return @cache[n] if @cache.key?(n) - - @cache[n] = fib(n - 1) + fib(n - 2) - - @cache[n] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - - - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## C# - -```csharp -public class Solution -{ - public int Fib(int n) - { - if (n <= 1) - return n; - - var dp = new int[n + 1]; - dp[1] = 1; - - for (var i = 2; i < dp.Length; i++) - { - dp[i] = dp[i - 1] + dp[i - 2]; - } - - return dp[n]; - } -} -``` - -## Python - -```python -class Solution: - def fib(self, n: int) -> int: - if n == 0: - return 0 - - dp = [0] * (n + 1) - dp[1] = 1 - - for i in range(2, len(dp)): - dp[i] = dp[i - 1] + dp[i - 2] - - return dp[-1] -``` - -## C++ - -```cpp -class Solution { -public: - int fib(int n) { - if (n <= 1) { - return n; - } - - auto dp = vector(n + 1); - dp[1] = 1; - - for (auto i = 2; i < dp.size(); i++) { - dp[i] = dp[i - 1] + dp[i - 2]; - } - - return dp[n]; - } -}; -``` - -## Java - -```java -class Solution { - public int fib(int n) { - if (n <= 1) { - return n; - } - - var dp = new int[n + 1]; - dp[1] = 1; - - for (var i = 2; i < dp.length; i++) { - dp[i] = dp[i - 1] + dp[i - 2]; - } - - return dp[n]; - } -} -``` - -## JavaScript - -```javascript -var fib = function (n) { - if (n <= 1) { - return n - } - - const dp = Array(n + 1).fill(0) - dp[1] = 1 - - for (let i = 2; i < dp.length; i++) { - dp[i] = dp[i - 1] + dp[i - 2] - } - - return dp[n] -}; -``` - -## Go - -```go -func fib(n int) int { - if n == 0 { - return 0 - } - - dp := make([]int, n + 1) - dp[1] = 1 - - for i := 2; i <= n; i++ { - dp[i] = dp[i - 2] + dp[i - 1] - } - - return dp[n] -} -``` - -## Ruby - -```ruby -def fib(n) - return 0 if n == 0 - - dp = Array.new(n + 1, 0) - dp[1] = 1 - - (2...dp.size).each do |i| - dp[i] = dp[i - 1] + dp[i - 2] - end - - dp[-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 3 - - - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## C# - -```csharp -public class Solution -{ - public int Fib(int n) - { - if (n <= 1) - return n; - - int[] dp = [0, 1]; - - for (var i = 2; i <= n; i++) - { - var dc = (int[])dp.Clone(); - - dp[0] = dc[1]; - dp[1] = dc[0] + dc[1]; - } - - return dp[1]; - } -} -``` - -## Python - -```python -class Solution: - def fib(self, n: int) -> int: - if n == 0: - return 0 - - dp = [0, 1] - - for i in range(2, n + 1): - dc = dp.copy() - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - - return dp[1] -``` - -## C++ - -```cpp -class Solution { -public: - int fib(int n) { - if (n <= 1) { - return n; - } - - vector dp = {0, 1}; - - for (auto i = 2; i <= n; i++) { - auto dc = dp; - - dp[0] = dc[1]; - dp[1] = dc[0] + dc[1]; - } - - return dp[1]; - } -}; -``` - -## Java - -```java -class Solution { - public int fib(int n) { - if (n <= 1) { - return n; - } - - int[] dp = {0, 1}; - - for (var i = 2; i <= n; i++) { - var dc = dp.clone(); - - dp[0] = dc[1]; - dp[1] = dc[0] + dc[1]; - } - - return dp[1]; - } -} -``` - -## JavaScript - -```javascript -var fib = function (n) { - if (n <= 1) { - return n - } - - const dp = [0, 1] - - for (let i = 2; i <= n; i++) { - const dc = [...dp] - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - } - - return dp[1] -}; -``` - -## Go - -```go -func fib(n int) int { - if n == 0 { - return 0 - } - - dp := []int{0, 1} - - for i := 2; i <= n; i++ { - dc := slices.Clone(dp) - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - } - - return dp[1] -} -``` - -## Ruby - -```ruby -def fib(n) - return 0 if n == 0 - - dp = [0, 1] - - (2..n).each do |i| - dc = dp.clone - - dp[0] = dc[1] - dp[1] = dc[0] + dc[1] - end - - dp[1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[509. 斐波那契数 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/509-fibonacci-number). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/518-coin-change-ii.md b/zh/1-1000/518-coin-change-ii.md deleted file mode 100644 index bc1c4cb..0000000 --- a/zh/1-1000/518-coin-change-ii.md +++ /dev/null @@ -1,186 +0,0 @@ -# 518. Coin Change II -LeetCode link: [518. Coin Change II](https://leetcode.com/problems/coin-change-ii/) - -## LeetCode problem description -> You are given an integer array `coins` representing coins of different denominations and an integer amount representing a total `amount` of money. - -Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return `0`. - -You may assume that you have an infinite number of each kind of coin. - -The answer is **guaranteed** to fit into a signed 32-bit integer. - -``` -Example 1: - -Input: amount = 5, coins = [1,2,5] -Output: 4 - -Explanation: there are four ways to make up the amount: -5=5 -5=2+2+1 -5=2+1+1+1 -5=1+1+1+1+1 ------------------------------------------------------------------------- - -Example 2: - -Input: amount = 3, coins = [2] -Output: 0 - -Explanation: the amount of 3 cannot be made up just with coins of 2. ------------------------------------------------------------------------- - -Example 3: - -Input: amount = 10, coins = [10] -Output: 1 ------------------------------------------------------------------------- - -Constraints: - -1 <= coins.length <= 300 -1 <= coins[i] <= 5000 -All the values of 'coins' are unique. -0 <= amount <= 5000 -``` - -## Thoughts -It is a `Unbounded Knapsack Problem`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n)`. - -## C# -```c# -public class Solution -{ - public int Change(int amount, int[] coins) - { - var dp = new int[amount + 1]; - dp[0] = 1; - - foreach (int coin in coins) - { - for (var j = coin; j < dp.Length; j++) - { - dp[j] += dp[j - coin]; - } - } - - return dp.Last(); - } -} -``` - -## Python -```python -class Solution: - def change(self, amount: int, coins: List[int]) -> int: - dp = [0] * (amount + 1) - dp[0] = 1 - - for coin in coins: - for j in range(coin, len(dp)): - dp[j] += dp[j - coin] - - return dp[-1] -``` - -## C++ -```cpp -class Solution { -public: - int change(int amount, vector& coins) { - auto dp = vector(amount + 1, 0); - dp[0] = 1; - - for (auto coin : coins) { - for (auto j = coin; j < dp.size(); j++) { - dp[j] += dp[j - coin]; - } - } - - return dp.back(); - } -}; -``` - -## Java -```java -class Solution { - public int change(int amount, int[] coins) { - var dp = new int[amount + 1]; - dp[0] = 1; - - for (var coin : coins) { - for (var j = coin; j < dp.length; j++) { - dp[j] += dp[j - coin]; - } - } - - return dp[dp.length - 1]; - } -} -``` - -## JavaScript -```javascript -var change = function (amount, coins) { - const dp = Array(amount + 1).fill(0) - dp[0] = 1 - - for (const coin of coins) { - for (let j = coin; j < dp.length; j++) { - dp[j] += dp[j - coin] - } - } - - return dp.at(-1); -}; -``` - -## Go -```go -func change(amount int, coins []int) int { - dp := make([]int, amount + 1) - dp[0] = 1 - - for _, coin := range coins { - for j := coin; j < len(dp); j++ { - dp[j] += dp[j - coin] - } - } - - return dp[len(dp) - 1] -} -``` - -## Ruby -```ruby -def change(amount, coins) - dp = Array.new(amount + 1, 0) - dp[0] = 1 - - coins.each do |coin| - (coin...dp.size).each do |j| - dp[j] += dp[j - coin] - end - end - - dp[-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/53-maximum-subarray.md b/zh/1-1000/53-maximum-subarray.md deleted file mode 100644 index 7dac03d..0000000 --- a/zh/1-1000/53-maximum-subarray.md +++ /dev/null @@ -1,397 +0,0 @@ -# 53. 最大子数组和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[53. 最大子数组和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/53-maximum-subarray),体验更佳! - -力扣链接:[53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray), 难度等级:**中等**。 - -## LeetCode “53. 最大子数组和”问题描述 - -给你一个整数数组 `nums` ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 - -**子数组**是数组中的一个连续部分。 - -### [示例 1] - -**输入**: `nums = [-2,1,-3,4,-1,2,1,-5,4]` - -**输出**: `6` - -**解释**: `连续子数组 [4,-1,2,1] 的和最大,为 6 。` - -### [示例 2] - -**输入**: `nums = [1]` - -**输出**: `1` - -**解释**: `The subarray [1] has the largest sum 1.` - -### [示例 3] - -**输入**: `nums = [5,4,-1,7,8]` - -**输出**: `23` - -**解释**: - -

The subarray [5,4,-1,7,8] has the largest sum 23.

- - -### [约束] - -- `1 <= nums.length <= 10^5` -- `-10^4 <= nums[i] <= 10^4` - -## 思路 1 - -- 本题可以用贪心算法解决(请看`方案2`),不过这里我们使用另一种方法。 -- 对于`nums[i]`: - 1. 如果`上一次的和`为负数,我们可以丢弃`上一次的和`; - 2. 如果`上一次的和`为正数,我们可以将`上一次的和`加到`当前和`中。 -- 因此,它符合`动态规划`问题的特点。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 步骤 - -### 动态规划的常用步骤 - -这五个步骤是解决`动态规划`问题的模式。 - -1. 确定`dp[i]`的**含义**。 - - 假设`dp[i]`表示索引`i`处的`最大和`。这样做行吗? - mark-detail `dp[i + 1]`无法通过`dp[i]`计算。所以我们必须改变这个含义。mark-detail - - 该如何设计呢? - mark-detail 如果`dp[i]`表示索引`i`处的`当前和`,`dp[i + 1]`就可以通过`dp[i]`计算。最后,我们就可以看到`最大和`记录在`当前和`数组中。mark-detail -2. 确定 `dp` 数组的初值。 - - ```ruby - nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - dp = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - ``` -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - - ```ruby - nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] - dp = [-2, 1, N, N, N, N, N, N, N] # N 表示现在不关注 - dp = [-2, 1, -2, N, N, N, N, N, N] - dp = [-2, 1, -2, 4, N, N, N, N, N] - dp = [-2, 1, -2, 4, 3, N, N, N, N] - dp = [-2, 1, -2, 4, 3, 5, N, N, N] - dp = [-2, 1, -2, 4, 3, 5, 6, N, N] - dp = [-2, 1, -2, 4, 3, 5, 6, 1, N] - dp = [-2, 1, -2, 4, 3, 5, 6, 1, 5] - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```python - dp[i] = max(nums[i], dp[i - 1] + nums[i]) - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 复杂度 - -- 时间复杂度: `O(n)`. -- 空间复杂度: `O(n)`. - -## Python - -```python -class Solution: - def maxSubArray(self, nums: List[int]) -> int: - dp = nums.copy() - - for i in range(1, len(dp)): - dp[i] = max(nums[i], dp[i - 1] + nums[i]) - - return max(dp) -``` - -## Java - -```java -class Solution { - public int maxSubArray(int[] nums) { - var dp = nums.clone(); - - for (var i = 1; i < dp.length; i++) { - dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]); - } - - return IntStream.of(dp).max().getAsInt(); // if you want to beat 99%, refer to C# soluiton's comment - } -} -``` - -## JavaScript - -```javascript -var maxSubArray = function (nums) { - const dp = [...nums] - - for (let i = 1; i < dp.length; i++) { - dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]) - } - - return Math.max(...dp) -}; -``` - -## Go - -```go -func maxSubArray(nums []int) int { - dp := slices.Clone(nums) - - for i := 1; i < len(nums); i++ { - dp[i] = max(nums[i], dp[i - 1] + nums[i]) - } - - return slices.Max(dp) -} -``` - -## Ruby - -```ruby -def max_sub_array(nums) - dp = nums.clone - - (1...dp.size).each do |i| - dp[i] = [ nums[i], dp[i - 1] + nums[i] ].max - end - - dp.max -end -``` - -## C# - -```csharp -public class Solution -{ - public int MaxSubArray(int[] nums) - { - var dp = (int[])nums.Clone(); - - for (var i = 1; i < dp.Length; i++) - { - dp[i] = Math.Max(nums[i], dp[i - 1] + nums[i]); - } - - return dp.Max(); // if you want to beat 99%, you can use a variable to collect the maximum value: `if (dp[i] > result) result = dp[i];` - } -} -``` - -## C++ - -```cpp -class Solution { -public: - int maxSubArray(vector& nums) { - auto dp = nums; - - for (auto i = 1; i < dp.size(); i++) { - dp[i] = max(nums[i], dp[i - 1] + nums[i]); - } - - return *max_element(dp.begin(), dp.end()); - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -- 本题的“贪心”算法解法和“动态规划”算法解法在本质上是一样的,都是“动态规划”,只不过此处的“贪心”算法把从使用`dp`一维数组,再降一个维度,变成了只使用两个变量。 -- 此处的“贪心”算法可以被称为“滚动变量”。就像“滚动数组(一维)”对应的是二维数组一样,一滚动就能降一个维度。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Python - -```python -class Solution: - def maxSubArray(self, nums: List[int]) -> int: - result = -float('inf') - pre_sum = 0 - - for num in nums: - pre_sum = max(pre_sum + num, num) - result = max(result, pre_sum) - - return result -``` - -## C++ - -```cpp -class Solution { -public: - int maxSubArray(vector& nums) { - int result = INT_MIN; - int pre_sum = 0; - - for (int num : nums) { - pre_sum = max(pre_sum + num, num); - result = max(result, pre_sum); - } - - return result; - } -}; -``` - -## Ruby - -```ruby -# @param {Integer[]} nums -# @return {Integer} -def max_sub_array(nums) - result = -Float::INFINITY - pre_sum = 0 - - nums.each do |num| - pre_sum = [pre_sum + num, num].max - result = [result, pre_sum].max - end - - result -end -``` - -## Go - -```go -func maxSubArray(nums []int) int { - result := math.MinInt - preSum := 0 - - for _, num := range nums { - preSum = max(preSum + num, num) - if preSum > result { - result = preSum - } - } - - return result -} -``` - -## JavaScript - -```javascript -/** - * @param {number[]} nums - * @return {number} - */ -var maxSubArray = function(nums) { - let result = -Infinity; - let preSum = 0; - - for (const num of nums) { - preSum = Math.max(preSum + num, num); - result = Math.max(result, preSum); - } - - return result; -}; -``` - -## C# - -```csharp -public class Solution -{ - public int MaxSubArray(int[] nums) - { - int result = int.MinValue; - int preSum = 0; - - foreach (int num in nums) - { - preSum = Math.Max(preSum + num, num); - result = Math.Max(result, preSum); - } - - return result; - } -} -``` - -## Java - -```java -class Solution { - public int maxSubArray(int[] nums) { - int result = Integer.MIN_VALUE; - int preSum = 0; - - for (int num : nums) { - preSum = Math.max(preSum + num, num); - result = Math.max(result, preSum); - } - - return result; - } -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[53. 最大子数组和 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/53-maximum-subarray). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/541-reverse-string-ii.md b/zh/1-1000/541-reverse-string-ii.md deleted file mode 100644 index c4af70d..0000000 --- a/zh/1-1000/541-reverse-string-ii.md +++ /dev/null @@ -1,285 +0,0 @@ -# 541. 反转字符串 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[541. 反转字符串 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/541-reverse-string-ii),体验更佳! - -力扣链接:[541. 反转字符串 II](https://leetcode.cn/problems/reverse-string-ii), 难度等级:**简单**。 - -## LeetCode “541. 反转字符串 II”问题描述 - -给定一个字符串 `s` 和一个整数 `k`,从字符串开头算起,每计数至 `2k` 个字符,就反转这 `2k` 字符中的前 `k` 个字符。 - -- 如果剩余字符少于 `k` 个,则将剩余字符全部反转。 -- 如果剩余字符小于 `2k` 但大于或等于 `k` 个,则反转前 `k` 个字符,其余字符保持原样。 - -### [示例 1] - -**输入**: `s = "abcdefg", k = 2` - -**输出**: `bacdfeg` - -### [示例 2] - -**输入**: `s = "abcd", k = 2` - -**输出**: `bacd` - -### [约束] - -- `1 <= s.length <= 10000` -- `s` consists of only lowercase English letters. -- `1 <= k <= 10000` - -## 思路 - -1. 题目没有要求`原地反转`,所以用一个新的字符串`result`作为返回值,操作起来容易些。 -2. 在循环中,步进值用`k`比`2k`更方便,因为如果用`2k`,还是要再用`k`做判断。 -3. 要求只反转`2k`字符中前`k`个字符,所以需要一个布尔类型变量`should_reverse`作为是否要反转判断条件。 - -## 步骤 - -1. 用一个新的字符串`result`作为返回值。在循环中,步进值用`k`。 - - ```ruby - result = '' - index = 0 - - while index < s.size - k_chars = s[index...index + k] - result += k_chars - index += k - end - - return result - ``` - -2. 用布尔类型变量`should_reverse`作为是否要反转判断条件,并只反转`2k`字符中前`k`个字符。 - - ```ruby - result = '' - should_reverse = true # 1 - index = 0 - - while index < s.size - k_chars = s[index...index + k] - - if should_reverse # 2 - result += k_chars.reverse # 3 - else # 4 - result += k_chars - end - - index += k - should_reverse = !should_reverse # 5 - end - - return result - ``` - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def reverseStr(self, s: str, k: int) -> str: - result = '' - should_reverse = True - index = 0 - - while index < len(s): - k_chars = s[index:index + k] - - if should_reverse: - result += k_chars[::-1] - else: - result += k_chars - - index += k - should_reverse = not should_reverse - - return result -``` - -## Java - -```java -class Solution { - public String reverseStr(String s, int k) { - var result = new StringBuffer(); - var shouldReverse = true; - var index = 0; - - while (index < s.length()) { - var kChars = s.substring(index, Math.min(index + k, s.length())); - - if (shouldReverse) { - result.append(new StringBuffer(kChars).reverse()); - } else { - result.append(kChars); - } - - index += k; - shouldReverse = !shouldReverse; - } - - return result.toString(); - } -} -``` - -## JavaScript - -```javascript -var reverseStr = function (s, k) { - let result = '' - let shouldReverse = true - let index = 0 - - while (index < s.length) { - const kChars = s.substr(index, k) - - if (shouldReverse) { - result += [...kChars].reverse().join('') - } else { - result += kChars - } - - index += k - shouldReverse = !shouldReverse - } - - return result -}; -``` - -## C# - -```csharp -public class Solution -{ - public string ReverseStr(string s, int k) - { - string result = ""; - bool shouldReverse = true; - int index = 0; - - while (index < s.Length) - { - string kChars = s[index..Math.Min(index + k, s.Length)]; - - if (shouldReverse) - { - result += new string(kChars.Reverse().ToArray()); - } - else - { - result += kChars; - } - - index += k; - shouldReverse = !shouldReverse; - } - - return result; - } -} -``` - -## Ruby - -```ruby -def reverse_str(s, k) - result = '' - should_reverse = true - index = 0 - - while index < s.size - k_chars = s[index...index + k] - - if should_reverse - result += k_chars.reverse - else - result += k_chars - end - - index += k - should_reverse = !should_reverse - end - - result -end -``` - -## C++ - -```cpp -class Solution { -public: - string reverseStr(string s, int k) { - string result = ""; - bool shouldReverse = true; - int index = 0; - - while (index < s.length()) { - auto kChars = s.substr(index, k); - - if (shouldReverse) { - reverse(kChars.begin(), kChars.end()); - } - - result += kChars; - index += k; - shouldReverse = !shouldReverse; - } - - return result; - } -}; -``` - -## Go - -```go -func reverseStr(s string, k int) string { - var result []rune - shouldReverse := true - index := 0 - - for index < len(s) { - end := index + k - if end > len(s) { - end = len(s) - } - kChars := []rune(s[index:end]) - - if shouldReverse { - for i, j := 0, len(kChars) - 1; i < j; i, j = i + 1, j - 1 { - kChars[i], kChars[j] = kChars[j], kChars[i] - } - } - - result = append(result, kChars...) - index += k - shouldReverse = !shouldReverse - } - - return string(result) -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[541. 反转字符串 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/541-reverse-string-ii). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/583-delete-operation-for-two-strings.md b/zh/1-1000/583-delete-operation-for-two-strings.md deleted file mode 100644 index 0337e59..0000000 --- a/zh/1-1000/583-delete-operation-for-two-strings.md +++ /dev/null @@ -1,336 +0,0 @@ -# 583. 两个字符串的删除操作 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[583. 两个字符串的删除操作 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/583-delete-operation-for-two-strings),体验更佳! - -力扣链接:[583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings), 难度等级:**中等**。 - -## LeetCode “583. 两个字符串的删除操作”问题描述 - -给定两个单词 `word1` 和 `word2` ,返回使得 `word1` 和 `word2` 相同所需的最小步数。 - -**每步** 可以删除任意一个字符串中的一个字符。 - -### [示例 1] - -**输入**: `word1 = "sea", word2 = "eat"` - -**输出**: `2` - -**解释**: `第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"` - -### [示例 2] - -**输入**: `word1 = "leetcode", word2 = "etco"` - -**输出**: `4` - -### [约束] - -- `1 <= word1.length, word2.length <= 500` -- `word1` 和 `word2` 只包含小写英文字母 - -## 思路 - -这是一道**比较两个字符串**的问题,属于处理“两个对等数组”。 -类似的题目做过多次后,我们会形成使用`二维数组`进行动态规划的直觉。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 步骤 - -1. 确定`dp[i][j]`的**含义**。 - - `dp[i][j]`表示使`word1`的前`i`个字母和`word2`的前`j`个字母相同所需的**最少**步数。 - - `dp[i][j]`是一个整数。 -2. 确定 `dp` 数组的初值。 - - 举例说明: - - ``` - 初始化后,'dp' 数组为: - # e a t - # 0 1 2 3 # dp[0] - # s 1 0 0 0 - # e 2 0 0 0 - # a 3 0 0 0 - ``` - - `dp[0][j] = j`,因为 `dp[0]` 表示空字符串,步数就是要删除的字符数。 - - `dp[i][0] = i`,理由和上一行一样,只是从垂直方向看。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - ``` - 1. word1 = "s", word2 = "eat" - # e a t - # 0 1 2 3 - # s 1 2 3 4 # dp[1] - ``` - ``` - 2. word1 = "se", word2 = "eat" - # e a t - # 0 1 2 3 - # s 1 2 3 4 - # e 2 1 2 3 - ``` - ``` - 3. word1 = "sea", word2 = "eat" - # e a t - # 0 1 2 3 - # s 1 2 3 4 - # e 2 1 2 3 - # a 3 2 1 2 - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```ruby - if word1[i - 1] == word2[j - 1] - dp[i][j] = dp[i - 1][j - 1] - else - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1 - end - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 复杂度 - -- 时间复杂度: `O(N * M)`. -- 空间复杂度: `O(N * M)`. - -## Java - -```java -class Solution { - public int minDistance(String word1, String word2) { - var dp = new int[word1.length() + 1][word2.length() + 1]; - for (var i = 0; i < dp.length; i++) { - dp[i][0] = i; - } - for (var j = 0; j < dp[0].length; j++) { - dp[0][j] = j; - } - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (word1.charAt(i - 1) == word2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1; - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public int MinDistance(string word1, string word2) - { - var dp = new int[word1.Length + 1, word2.Length + 1]; - - for (var i = 0; i < dp.GetLength(0); i++) - dp[i, 0] = i; - - for (var j = 0; j < dp.GetLength(1); j++) - dp[0, j] = j; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (word1[i - 1] == word2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1]; - } - else - { - dp[i, j] = Math.Min(dp[i - 1, j], dp[i, j - 1]) + 1; - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Python - -```python -class Solution: - def minDistance(self, word1: str, word2: str) -> int: - dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)] - for i in range(len(dp)): - dp[i][0] = i - for j in range(len(dp[0])): - dp[0][j] = j - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if word1[i - 1] == word2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1 - - return dp[-1][-1] -``` - -## C++ - -```cpp -class Solution { -public: - int minDistance(string word1, string word2) { - vector> dp(word1.size() + 1, vector(word2.size() + 1)); - for (auto i = 0; i < dp.size(); i++) { - dp[i][0] = i; - } - for (auto j = 0; j < dp[0].size(); j++) { - dp[0][j] = j; - } - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1; - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript - -```javascript -var minDistance = function (word1, word2) { - const dp = Array(word1.length + 1).fill().map( - () => Array(word2.length + 1).fill(0) - ) - dp.forEach((_, i) => { dp[i][0] = i }) - dp[0].forEach((_, j) => { dp[0][j] = j }) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go - -```go -func minDistance(word1 string, word2 string) int { - dp := make([][]int, len(word1) + 1) - for i := range dp { - dp[i] = make([]int, len(word2) + 1) - dp[i][0] = i - } - for j := range dp[0] { - dp[0][j] = j - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if word1[i - 1] == word2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby - -```ruby -def min_distance(word1, word2) - dp = Array.new(word1.size + 1) do - Array.new(word2.size + 1, 0) - end - dp.each_with_index do |_, i| - dp[i][0] = i - end - dp[0].each_with_index do |_, j| - dp[0][j] = j - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if word1[i - 1] == word2[j - 1] - dp[i - 1][j - 1] - else - [ dp[i - 1][j], dp[i][j - 1] ].min + 1 - end - end - end - - dp[-1][-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[583. 两个字符串的删除操作 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/583-delete-operation-for-two-strings). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/59-spiral-matrix-ii.md b/zh/1-1000/59-spiral-matrix-ii.md deleted file mode 100644 index ced8f60..0000000 --- a/zh/1-1000/59-spiral-matrix-ii.md +++ /dev/null @@ -1,417 +0,0 @@ -# 59. 螺旋矩阵 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[59. 螺旋矩阵 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/59-spiral-matrix-ii),体验更佳! - -力扣链接:[59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii), 难度等级:**中等**。 - -## LeetCode “59. 螺旋矩阵 II”问题描述 - -给你一个正整数 `n` ,生成一个包含 *1* 到 *n2* 所有元素,且元素按顺时针顺序螺旋排列的 `n x n` 正方形矩阵 `matrix` 。 - -### [示例 1] - -![](../../images/examples/59_1.jpg) - -**输入**: `n = 3` - -**输出**: `[[1,2,3],[8,9,4],[7,6,5]]` - -### [示例 2] - -**输入**: `n = 1` - -**输出**: `[[1]]` - -### [约束] - -- `1 <= n <= 20` - -## 思路 - -- 本题的难点在于在二维数组中,如何获得当前位置的下一个位置。 - -- 可以写一个方法`get_increment(i, j)`,专门用于获得下一个位置与当前位置相比的变化量。 - -## 步骤 - -1. 初始化 `increments` 和 `increment_index`: - - ```python - increments = [(0, 1), (1, 0), (0, -1), (-1, 0)] # (i, j) right, down, left, up - increment_index = 0 - ``` - -2. 核心逻辑: - - ```python - while num <= n * n: - matrix[i][j] = num - num += 1 - - increment = get_increment(i, j) - i += increment[0] - j += increment[1] - ``` - -3. 对于函数 `get_increment(i, j)`,它应该返回一对 `[0, 1]`。首先验证当前增量是否有效。如果无效,则使用下一个增量。 - - ```python - def get_increment(i, j): - increment = increments[increment_index] - i += increment[0] - j += increment[1] - - if ( - i < 0 or i >= len(matrix) or - j < 0 or j >= len(matrix) or - matrix[i][j] is not None - ): # 当前增量无效,使用下一个增量 - increment_index += 1 - increment_index %= len(self.increments) - - return increments[increment_index] - ``` - -## 复杂度 - -- 时间复杂度: `O(N * N)`. -- 空间复杂度: `O(N * N)`. - -## Java - -```java -class Solution { - private int[][] matrix; - private int[][] increments = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - private int incrementIndex = 0; - - public int[][] generateMatrix(int n) { - matrix = new int[n][n]; - var i = 0; - var j = 0; - var num = 1; - - while (num <= n * n) { - matrix[i][j] = num; - num++; - - var increment = getIncrement(i, j); - i += increment[0]; - j += increment[1]; - } - - return matrix; - } - - private int[] getIncrement(int i, int j) { - var increment = increments[incrementIndex]; - i += increment[0]; - j += increment[1]; - - if ( - i < 0 || i >= matrix.length || - j < 0 || j >= matrix.length || - matrix[i][j] > 0 - ) { - incrementIndex += 1; - incrementIndex %= increments.length; - } - - return increments[incrementIndex]; - } -} -``` - -## Python - -```python -class Solution: - def __init__(self): - self.matrix = None - self.increments = [(0, 1), (1, 0), (0, -1), (-1, 0)] - self.increment_index = 0 - - def generateMatrix(self, n: int) -> List[List[int]]: - self.matrix = [[None] * n for _ in range(n)] - i = 0 - j = 0 - num = 1 - - while num <= n * n: - self.matrix[i][j] = num - num += 1 - - increment = self.get_increment(i, j) - i += increment[0] - j += increment[1] - - return self.matrix - - def get_increment(self, i, j): - increment = self.increments[self.increment_index] - i += increment[0] - j += increment[1] - - if ( - i < 0 or i >= len(self.matrix) or - j < 0 or j >= len(self.matrix) or - self.matrix[i][j] - ): - self.increment_index += 1 - self.increment_index %= len(self.increments) - - return self.increments[self.increment_index] -``` - -## JavaScript - -```javascript -let matrix -const increments = [[0, 1], [1, 0], [0, -1], [-1, 0]] -let incrementIndex - -var generateMatrix = function (n) { - matrix = Array(n).fill().map(() => Array(n).fill(0)) - incrementIndex = 0 - - let i = 0 - let j = 0 - let num = 1 - - while (num <= n * n) { - matrix[i][j] = num - num++ - - const increment = getIncrement(i, j) - i += increment[0] - j += increment[1] - } - - return matrix -}; - -function getIncrement(i, j) { - const increment = increments[incrementIndex] - i += increment[0] - j += increment[1] - - if ( - i < 0 || i >= matrix.length || - j < 0 || j >= matrix.length || - matrix[i][j] > 0 - ) { - incrementIndex += 1 - incrementIndex %= increments.length - } - - return increments[incrementIndex] -} -``` - -## C# - -```csharp -public class Solution -{ - int[][] matrix; - int[][] increments = { new[] {0, 1}, new[] {1, 0}, new[] {0, -1}, new[] {-1, 0} }; - int incrementIndex = 0; - - public int[][] GenerateMatrix(int n) - { - matrix = new int[n][]; - - for (int k = 0; k < n; k++) - matrix[k] = new int[n]; - - int i = 0; - int j = 0; - int num = 1; - - while (num <= n * n) - { - matrix[i][j] = num; - num++; - - int[] increment = getIncrement(i, j); - i += increment[0]; - j += increment[1]; - } - - return matrix; - } - - int[] getIncrement(int m, int n) - { - int[] increment = increments[incrementIndex]; - int i = m + increment[0]; - int j = n + increment[1]; - - if ( - i < 0 || i >= matrix.GetLength(0) || - j < 0 || j >= matrix.GetLength(0) || - matrix[i][j] > 0 - ) - { - incrementIndex += 1; - incrementIndex %= increments.Length; - } - - return increments[incrementIndex]; - } -} -``` - -## Ruby - -```ruby -def generate_matrix(n) - @matrix = Array.new(n) { Array.new(n) } - @increments = [[0, 1], [1, 0], [0, -1], [-1, 0]] - @increment_index = 0 - - i = 0 - j = 0 - num = 1 - - while num <= n * n - @matrix[i][j] = num - num += 1 - - increment = get_increment(i, j) - i += increment[0] - j += increment[1] - end - - @matrix -end - -private - -def get_increment(i, j) - increment = @increments[@increment_index] - next_i = i + increment[0] - next_j = j + increment[1] - - if next_i < 0 || next_i >= @matrix.size || - next_j < 0 || next_j >= @matrix.size || - @matrix[next_i][next_j] - @increment_index += 1 - @increment_index %= @increments.size - end - - @increments[@increment_index] -end -``` - -## Go - -```go -type spiralMatrix struct { - matrix [][]int - increments [][2]int - incrementIndex int -} - -func (sm *spiralMatrix) getIncrement(i, j int) [2]int { - currentIncrement := sm.increments[sm.incrementIndex] - nextI := i + currentIncrement[0] - nextJ := j + currentIncrement[1] - - if nextI < 0 || nextI >= len(sm.matrix) || - nextJ < 0 || nextJ >= len(sm.matrix) || - sm.matrix[nextI][nextJ] != 0 { - sm.incrementIndex = (sm.incrementIndex + 1) % len(sm.increments) - } - return sm.increments[sm.incrementIndex] -} - -func generateMatrix(n int) [][]int { - sm := &spiralMatrix{ - matrix: make([][]int, n), - increments: [][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, - incrementIndex: 0, - } - - for i := range sm.matrix { - sm.matrix[i] = make([]int, n) - } - - i, j, num := 0, 0, 1 - - for num <= n * n { - sm.matrix[i][j] = num - num++ - - increment := sm.getIncrement(i, j) - i += increment[0] - j += increment[1] - } - - return sm.matrix -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> generateMatrix(int n) { - matrix_ = vector>(n, vector(n, 0)); - increments_ = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - increment_index_ = 0; - - int i = 0; - int j = 0; - int num = 1; - - while (num <= n * n) { - matrix_[i][j] = num; - num++; - - vector increment = getIncrement(i, j); - i += increment[0]; - j += increment[1]; - } - - return matrix_; - } - -private: - vector> matrix_; - vector> increments_; - int increment_index_; - - vector getIncrement(int i, int j) { - vector increment = increments_[increment_index_]; - int next_i = i + increment[0]; - int next_j = j + increment[1]; - - if ( - next_i < 0 || next_i >= matrix_.size() || - next_j < 0 || next_j >= matrix_.size() || - matrix_[next_i][next_j] > 0 - ) { - increment_index_++; - increment_index_ %= increments_.size(); - } - - return increments_[increment_index_]; - } -}; -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[59. 螺旋矩阵 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/59-spiral-matrix-ii). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/605-can-place-flowers.md b/zh/1-1000/605-can-place-flowers.md deleted file mode 100644 index caec650..0000000 --- a/zh/1-1000/605-can-place-flowers.md +++ /dev/null @@ -1,224 +0,0 @@ -# 605. 种花问题 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[605. 种花问题 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/605-can-place-flowers),体验更佳! - -力扣链接:[605. 种花问题](https://leetcode.cn/problems/can-place-flowers), 难度等级:**简单**。 - -## LeetCode “605. 种花问题”问题描述 - -假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花**不能种植在相邻**的地块上,它们会争夺水源,两者都会死去。 - -给你一个整数数组 `flowerbed` 表示花坛,由若干 `0` 和 `1` 组成,其中 `0` 表示没种植花,`1` 表示种植了花。另有一个数 `n` ,能否在不打破种植规则的情况下种入 `n` 朵花?能则返回 `true` ,不能则返回 `false` 。 - -### [示例 1] - -**输入**: `flowerbed = [1,0,0,0,1], n = 1` - -**输出**: `true` - -### [示例 2] - -**输入**: `flowerbed = [1,0,0,0,1], n = 2` - -**输出**: `false` - -### [约束] - -- `1 <= flowerbed.length <= 2 * 10^4` -- `flowerbed[i]` 为 `0` 或 `1` -- `flowerbed` 中不存在相邻的两朵花 -- `0 <= n <= flowerbed.length` - -## 思路 - -检查每个空地块(`0`),若其左右均为空(或边界),则可种花(置`1`),并计数。若最终计数≥`n`,返回`true`,否则`false`。 - -## 步骤 - -1. 初始化计数器`count = 0`。 -2. 遍历花坛每个地块: - - 若当前为`1`,跳过。 - - 若当前为`0`且左右均为`0`(或边界),则种花(置`1`),`count += 1`。 -3. 返回`count >= n`。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(1)`. - -## Python - -```python -class Solution: - def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: - count = 0 - - for i in range(len(flowerbed)): - if flowerbed[i] == 1: - continue - - if (i == 0 or flowerbed[i - 1] == 0) and \ - (i == len(flowerbed) - 1 or flowerbed[i + 1] == 0): - flowerbed[i] = 1 - count += 1 - - return count >= n -``` - -## Java - -```java -class Solution { - public boolean canPlaceFlowers(int[] flowerbed, int n) { - int count = 0; - - for (int i = 0; i < flowerbed.length; i++) { - if (flowerbed[i] == 1) { - continue; - } - - if ((i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - bool canPlaceFlowers(vector& flowerbed, int n) { - int count = 0; - - for (int i = 0; i < flowerbed.size(); i++) { - if (flowerbed[i] == 1) { - continue; - } - - if ((i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.size() - 1 || flowerbed[i + 1] == 0)) { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; - } -}; -``` - -## JavaScript - -```javascript -var canPlaceFlowers = function(flowerbed, n) { - let count = 0; - - for (let i = 0; i < flowerbed.length; i++) { - if (flowerbed[i] === 1) { - continue; - } - - if ((i === 0 || flowerbed[i - 1] === 0) && - (i === flowerbed.length - 1 || flowerbed[i + 1] === 0)) { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; -}; - -``` - -## Go - -```go -func canPlaceFlowers(flowerbed []int, n int) bool { - count := 0 - - for i := 0; i < len(flowerbed); i++ { - if flowerbed[i] == 1 { - continue - } - - if (i == 0 || flowerbed[i - 1] == 0) && - (i == len(flowerbed) - 1 || flowerbed[i + 1] == 0) { - flowerbed[i] = 1 - count++ - } - } - - return count >= n -} - -``` - -## C# - -```csharp -public class Solution -{ - public bool CanPlaceFlowers(int[] flowerbed, int n) - { - int count = 0; - - for (int i = 0; i < flowerbed.Length; i++) - { - if (flowerbed[i] == 1) - { - continue; - } - - if ((i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.Length - 1 || flowerbed[i + 1] == 0)) - { - flowerbed[i] = 1; - count++; - } - } - - return count >= n; - } -} -``` - -## Ruby - -```ruby -def can_place_flowers(flowerbed, n) - count = 0 - - flowerbed.each_with_index do |plot, i| - next if plot == 1 - - if (i == 0 || flowerbed[i - 1] == 0) && - (i == flowerbed.length - 1 || flowerbed[i + 1] == 0) - flowerbed[i] = 1 - count += 1 - end - end - - count >= n -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[605. 种花问题 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/605-can-place-flowers). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/674-longest-continuous-increasing-subsequence.md b/zh/1-1000/674-longest-continuous-increasing-subsequence.md deleted file mode 100644 index cbbf041..0000000 --- a/zh/1-1000/674-longest-continuous-increasing-subsequence.md +++ /dev/null @@ -1,162 +0,0 @@ -# 674. Longest Continuous Increasing Subsequence -LeetCode link: [674. Longest Continuous Increasing Subsequence](https://leetcode.com/problems/longest-continuous-increasing-subsequence/) - -## LeetCode problem description -Given an integer array `nums`, return the length of the **longest strictly increasing subsequence**. - -``` ----------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums = [10,9,2,5,3,7,101,18] -Output: 4 - -Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. ----------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums = [0,1,0,3,2,3] -Output: 4 ----------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums = [7,7,7,7,7,7,7] -Output: 1 ----------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums.length <= 2500 --10000 <= nums[i] <= 10000 ----------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 4 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## C# -```c# -// [1, 3, 5, 4, 3, 6, 2, 4, 5, 7, 4] # nums -// [1, 2, 3, 1, 1, 2, 1, 2, 3, 4, 1] # dp -public class Solution -{ - public int FindLengthOfLCIS(int[] nums) - { - var dp = new int[nums.Length]; - Array.Fill(dp, 1); - - for (var i = 1; i < nums.Length; i++) - { - if (nums[i] > nums[i - 1]) - { - dp[i] = dp[i - 1] + 1; - } - } - - return dp.Max(); // If you want to beat 90%, refer to Java code. - } -} -``` - -## Java -```java -class Solution { - public int findLengthOfLCIS(int[] nums) { - var result = 1; - var dp = new int[nums.length]; - Arrays.fill(dp, 1); - - for (var i = 1; i < nums.length; i++) { - if (nums[i] > nums[i - 1]) { - dp[i] = dp[i - 1] + 1; - result = Math.max(result, dp[i]); - } - } - - return result; - } -} -``` - -## Python -### Solution 1 -```python -class Solution: - def findLengthOfLCIS(self, nums: List[int]) -> int: - dp = [1] * len(nums) - - for i, num in enumerate(nums): - if i == 0: - continue - - if num > nums[i - 1]: - dp[i] = dp[i - 1] + 1 - - return max(dp) -``` - -### Solution 2 -```python -class Solution: - def findLengthOfLCIS(self, nums: List[int]) -> int: - result = 1 - current_length = 1 - - for i in range(1, len(nums)): - if nums[i] > nums[i - 1]: - current_length += 1 - - if current_length > result: - result = current_length - else: - current_length = 1 - - return result -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var findLengthOfLCIS = function (nums) { - const dp = Array(nums.length).fill(1) - - nums.forEach((num, i) => { - for (let j = i - 1; j >= 0; j--) { - if (num > nums[i - 1]) { - dp[i] = dp[i - 1] + 1 - } - } - }) - - return Math.max(...dp) // If you want to beat 90%, refer to Java code. -}; -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/684-redundant-connection.md b/zh/1-1000/684-redundant-connection.md deleted file mode 100644 index 6ac56f3..0000000 --- a/zh/1-1000/684-redundant-connection.md +++ /dev/null @@ -1,409 +0,0 @@ -# LeetCode 684. Redundant Connection's Solution -LeetCode link: [684. Redundant Connection](https://leetcode.com/problems/redundant-connection) - -## LeetCode problem description -In this problem, a tree is an **undirected graph** that is connected and has no cycles. - -You are given a graph that started as a tree with `n` nodes labeled from `1` to `n`, with one additional edge added. The added edge has two **different** vertices chosen from `1` to `n`, and was not an edge that already existed. The graph is represented as an array `edges` of length `n` where `edges[i] = [ai, bi]` indicates that there is an edge between nodes `ai` and `bi` in the graph. - -Return an edge that can be removed so that the resulting graph is a tree of `n` nodes. If there are multiple answers, return the answer that occurs last in the input. - -### Example 1 -![](../../images/examples/684_1.jpg) -``` -Input: edges = [[1,2],[1,3],[2,3]] -Output: [2,3] -``` - -### Example 2 -![](../../images/examples/684_2.jpg) -``` -Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]] -Output: [1,4] -``` - -### Constraints -- `n == edges.length` -- `3 <= n <= 1000` -- `edges[i].length == 2` -- `1 <= ai < bi <= edges.length` -- `ai != bi` -- There are no repeated edges. -- The given graph is connected. - -## Intuition -- In graph theory, a tree is an _undirected graph_ in which any two vertices are connected by exactly one path, or equivalently a **connected acyclic undirected graph**. Like this: -![A labeled tree with six vertices and five edges.](../../images/graph_tree_1.png) - -- When an edge is added to the graph, its two nodes are also added to the graph. -- If the two nodes are already in the graph, then they must be on the same tree. At this time, a cycle is bound to be formed. - -![](../../images/684.png) - -- We are given `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**. -- Finally, those trees can be merged into one tree if the redundant edge is removed. -- `UnionFind` algorithm is designed for grouping and searching data. - -### 'UnionFind' algorithm -- `UnionFind` algorithm typically has three methods: - - The `unite(node1, node2)` operation is used to merge two trees. - - The `find_root(node)` method is used to return the root of a node. - - The `is_same_root(node1, node2) == true` method is used to determine whether two nodes are in the same tree. - -## Approach (UnionFind algorithm) -1. Initially, each node is in its own group. -1. Iterate `edges` data and `unite(node1, node2)`. -1. As soon as `is_same_root(node1, node2) == true` (a cycle will be formed), return `[node1, node2]`. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: - self.parents = list(range(len(edges) + 1)) - - for x, y in edges: - if self.is_same_root(x, y): - return [x, y] - - self.unite(x, y) - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x # Error-prone point 1 - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) # Error-prone point 2 - - self.parents[x] = root # Error-prone point 3 - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -## Java -```java -class Solution { - private int[] parents; - - public int[] findRedundantConnection(int[][] edges) { - parents = new int[edges.length + 1]; - - for (var i = 0; i < parents.length; i++) { - parents[i] = i; - } - - for (var edge : edges) { - if (isSameRoot(edge[0], edge[1])) { - return edge; - } - - unite(edge[0], edge[1]); - } - - return null; - } - - private void unite(int x, int y) { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - private int findRoot(int x) { - var parent = parents[x]; - - if (x == parent) { - return x; - } - - var root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - private boolean isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -} -``` - -## C++ -```cpp -class Solution { -public: - vector findRedundantConnection(vector>& edges) { - for (auto i = 0; i <= edges.size(); i++) { - parents.push_back(i); - } - - for (auto& edge : edges) { - if (isSameRoot(edge[0], edge[1])) { - return edge; - } - - unite(edge[0], edge[1]); - } - - return {}; - } - -private: - vector parents; - - void unite(int x, int y) { - int root_x = findRoot(x); - int root_y = findRoot(y); - - parents[root_y] = root_x; // Error-prone point 1 - } - - int findRoot(int x) { - auto parent = parents[x]; - - if (x == parent) { - return x; - } - - auto root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -}; -``` - -## JavaScript -```javascript -let parents - -var findRedundantConnection = function(edges) { - parents = [] - for (let i = 0; i <= edges.length; i++) { - parents.push(i) - } - - for (let [x, y] of edges) { - if (isSameRoot(x, y)) { - return [x, y] - } - - unite(x, y) - } - - return isSameRoot(source, destination) -}; - -function unite(x, y) { - rootX = findRoot(x) - rootY = findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -function findRoot(x) { - const parent = parents[x] - - if (x == parent) { - return x - } - - const root = findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -function isSameRoot(x, y) { - return findRoot(x) == findRoot(y) -} -``` - -## C# -```c# -public class Solution -{ - int[] parents; - - public int[] FindRedundantConnection(int[][] edges) - { - parents = new int[edges.Length + 1]; - - for (int i = 0; i < parents.Length; i++) - parents[i] = i; - - foreach (int[] edge in edges) - { - if (isSameRoot(edge[0], edge[1])) - { - return edge; - } - - unite(edge[0], edge[1]); - } - - return null; - } - - void unite(int x, int y) - { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - int findRoot(int x) - { - int parent = parents[x]; - - if (x == parent) - return x; - - int root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) - { - return findRoot(x) == findRoot(y); - } -} -``` - -## Go -```go -var parents []int - -func findRedundantConnection(edges [][]int) []int { - parents = make([]int, len(edges) + 1) - for i := 0; i < len(parents); i++ { - parents[i] = i - } - - for _, edge := range edges { - if isSameRoot(edge[0], edge[1]) { - return edge - } - - unite(edge[0], edge[1]) - } - - return nil -} - -func unite(x, y int) { - rootX := findRoot(x) - rootY := findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -func findRoot(x int) int { - parent := parents[x]; - - if x == parent { - return x - } - - root := findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -func isSameRoot(x, y int) bool { - return findRoot(x) == findRoot(y) -} -``` - -## Ruby -```ruby -def find_redundant_connection(edges) - @parents = [] - (0..edges.size).each { |i| @parents << i } - - edges.each do |edge| - if is_same_root(edge[0], edge[1]) - return edge - end - - unite(edge[0], edge[1]) - end -end - -def unite(x, y) - root_x = find_root(x) - root_y = find_root(y) - - @parents[root_y] = root_x # Error-prone point 1 -end - -def find_root(x) - parent = @parents[x] - - if x == parent - return x - end - - root = find_root(parent) # Error-prone point 2 - - @parents[x] = root # Error-prone point 3 - - root -end - -def is_same_root(x, y) - find_root(x) == find_root(y) -end -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/685-redundant-connection-ii.md b/zh/1-1000/685-redundant-connection-ii.md deleted file mode 100644 index 55867a5..0000000 --- a/zh/1-1000/685-redundant-connection-ii.md +++ /dev/null @@ -1,183 +0,0 @@ -# LeetCode 685. Redundant Connection II's Solution -LeetCode link: [685. Redundant Connection II](https://leetcode.com/problems/redundant-connection-ii) - -## LeetCode problem description -In this problem, a rooted tree is a **directed** graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents. - -The given input is a directed graph that started as a rooted tree with `n` nodes (with distinct values from `1` to `n`), with one additional directed edge added. The added edge has two different vertices chosen from `1` to `n`, and was not an edge that already existed. - -The resulting graph is given as a 2D-array of `edges`. Each element of `edges` is a pair `[ui, vi]` that represents a directed edge connecting nodes `ui` and `vi`, where `ui` is a parent of child `vi`. - -Return _an edge that can be removed so that the resulting graph is a rooted tree of `n` nodes_. If there are multiple answers, return the answer that occurs last in the given 2D-array. - -### Example 1 -![](../../images/examples/685_1.jpg) -```java -Input: edges = [[1,2],[1,3],[2,3]] -Output: [2,3] -``` - -### Example 2 -![](../../images/examples/685_2.jpg) -```java -Input: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]] -Output: [4,1] -``` - -### Constraints -- `n == edges.length` -- `3 <= n <= 1000` -- `edges[i].length == 2` -- `1 <= ui, vi <= n` -- `ui != vi` - -## Intuition -- Because a cycle is formed, the directed tree is no longer a directed tree. There are two cases to consider: - 1. If there is a vertex with in-degree 2, it will form a cycle. So one of the edges needs to be removed (returned). - 2. If there is no vertex with in-degree 2, once a cycle is formed, return the edge that causes the cycle. - -- We are given `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**. -- Finally, those trees can be merged into one tree if the redundant edge is removed. -- `UnionFind` algorithm is designed for grouping and searching data. - -### 'UnionFind' algorithm -- `UnionFind` algorithm typically has three methods: - - The `unite(node1, node2)` operation is used to merge two trees. - - The `find_root(node)` method is used to return the root of a node. - - The `is_same_root(node1, node2)` method is used to determine whether two nodes are in the same tree. - -## Approach -1. Iterate `edges` data to look for the `two_conflict_edges` (the two edges caused a vertex with in-degree 2). -1. Initially, each node is in its own group. -1. Iterate `edges` data and `unite(node1, node2)`. -1. If there is no vertex with in-degree 2, as soon as `is_same_root(node1, node2) == true` (a cycle will be formed), return `[node1, node2]`. -1. If there is a vertex with in-degree 2, we need to determine which edge in `two_conflict_edges` should be returned. -See if the graph can form a cycle by not adding the second edge to the graph. If so, return the first edge. Otherwise, return the second edge. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def findRedundantDirectedConnection(self, edges: List[List[int]]) -> List[int]: - self.parents = list(range(len(edges) + 1)) - - two_conflict_edges_ = self.two_conflict_edges(edges) - - if not two_conflict_edges_: - for x, y in edges: - if self.is_same_root(x, y): - return [x, y] - - self.unite(x, y) - - raise Exception('No suitable edge was returned!') - - for x, y in edges: - if [x, y] == two_conflict_edges_[1]: - continue - - if self.is_same_root(x, y): - return two_conflict_edges_[0] - - self.unite(x, y) - - return two_conflict_edges_[1] - - def two_conflict_edges(self, edges): - pointed_node_to_source_node = {} - - for source_node, pointed_node in edges: - if pointed_node in pointed_node_to_source_node: - return [ - [pointed_node_to_source_node[pointed_node], pointed_node], - [source_node, pointed_node], - ] - - pointed_node_to_source_node[pointed_node] = source_node - - return [] - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) - - self.parents[x] = root - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Python -```python -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/695-max-area-of-island.md b/zh/1-1000/695-max-area-of-island.md deleted file mode 100644 index 7984483..0000000 --- a/zh/1-1000/695-max-area-of-island.md +++ /dev/null @@ -1,419 +0,0 @@ -# 695. Max Area of Island (Solution 1: 'Depth-First Search' by Recursion) -LeetCode link: [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/) - -# LeetCode problem description -You are given an `m x n` binary matrix `grid`. An island is a group of `1`'s (representing land) connected **4-directionally** (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. - -The `area` of an island is the number of cells with a value `1` in the island. - -Return _the maximum area of an island_ in `grid`. If there is no island, return `0`. - -## Example 1 -![](../../images/examples/695_1.jpg) -``` -Input: grid = [ - [0,0,1,0,0,0,0,1,0,0,0,0,0], - [0,0,0,0,0,0,0,1,1,1,0,0,0], - [0,1,1,0,1,0,0,0,0,0,0,0,0], - [0,1,0,0,1,1,0,0,1,0,1,0,0], - [0,1,0,0,1,1,0,0,1,1,1,0,0], - [0,0,0,0,0,0,0,0,0,0,1,0,0], - [0,0,0,0,0,0,0,1,1,1,0,0,0], - [0,0,0,0,0,0,0,1,1,0,0,0,0] -] -Output: 6 -Explanation: The answer is not 11, because the island must be connected 4-directionally. -``` - -## Example 2 -``` -Input: grid = [[0,0,0,0,0,0,0,0]] -Output: 0 -``` - -## Constraints -- `m == grid.length` -- `n == grid[i].length` -- `1 <= m, n <= 50` -- `grid[i][j]` is either `0` or `1`. - -## Intuition -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -Return _the maximum area of an island_ is to return the vertex count of the largest **connected component**. - -## Approach -1. Find the first land. -2. Starting at the first land, find all the lands of the island. - * There are two major ways to explore a `connected component` (island): **Breadth-First Search** and **Depth-First Search**. - * For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. So I will provide 3 solutions in total. - * When we traverse each `connected components` (island), we can: - * Mark each found land as `8` which represents `visited` (or `included` in `area`). Visited lands don't need to be visited again. - * **count** the lands of the island. -3. After all lands on an island have been visited, look for the next non-visited land. -4. Repeat the above two steps until all the lands have been `visited`. -5. At last, return the `max_area`. - -## Solution 1: 'Depth-First Search' by Recursion -![](../../images/binary_tree_DFS_1.png) - -From this sample code bellow, you can see that starting from a vertex, through recursive calls, it goes up until it can't go any further, turns right, and continues up. The priority order of directions is `up, right, down, left`. -```java -depth_first_search(i - 1, j); // up -depth_first_search(i, j + 1); // right -depth_first_search(i + 1, j); // down -depth_first_search(i, j - 1); // left -``` - -## Solution 2: 'Depth-First Search' by Iteration -Similar problem is `200. Number of Islands`, please click [Depth-First Search by Iteration Solution](200-number-of-islands-2.md) to view. - -## Solution 3: Breadth-First Search -Similar problem is `200. Number of Islands`, please click [Breadth-First Search Solution](200-number-of-islands-3.md) to view. - -## Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -# Python -```python -class Solution: - def __init__(self): - self.max_area = 0 - self.area = 0 - self.grid = None - - def maxAreaOfIsland(self, grid: List[List[int]]) -> int: - self.grid = grid - - for i in range(len(grid)): - for j in range(len(grid[0])): - if grid[i][j] == 1: - self.area = 0 - self.depth_first_search(i, j) - self.max_area = max(self.max_area, self.area) - - return self.max_area - - def depth_first_search(self, i, j): - if i < 0 or j < 0 or i >= len(self.grid) or j >= len(self.grid[0]): - return - - if self.grid[i][j] != 1: - return - - self.grid[i][j] = 8 - self.area += 1 - - for m, n in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0), - ]: - self.depth_first_search(i + m, j + n) -``` - -# Java -```java -class Solution { - int[][] grid; - int maxArea = 0; - int area = 0; - - public int maxAreaOfIsland(int[][] grid) { - this.grid = grid; - - for (var i = 0; i < grid.length; i++) { - for (var j = 0; j < grid[0].length; j++) { - if (grid[i][j] == 1) { - area = 0; - depthFirstSearch(i, j); - maxArea = Math.max(maxArea, area); - } - } - } - - return maxArea; - } - - void depthFirstSearch(int i, int j) { - if (i < 0 || i >= grid.length) { - return; - } - - if (j < 0 || j >= grid[0].length) { - return; - } - - if (grid[i][j] != 1) { - return; - } - - grid[i][j] = 8; - area++; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# C++ -```cpp -class Solution { -public: - int maxAreaOfIsland(vector>& grid) { - grid_ = grid; - - for (auto i = 0; i < grid_.size(); i++) { - for (auto j = 0; j < grid_[0].size(); j++) { - if (grid_[i][j] == 1) { - area_ = 0; - depth_first_search(i, j); - max_area_ = max(max_area_, area_); - } - } - } - - return max_area_; - } - -private: - vector> grid_; - int max_area_ = 0; - int area_ = 0; - - void depth_first_search(int i, int j) { - if ( - i < 0 || i >= grid_.size() || - j < 0 || j >= grid_[0].size() || - grid_[i][j] != 1 - ) { - return; - } - - grid_[i][j] = 8; - area_++; - - depth_first_search(i - 1, j); - depth_first_search(i, j + 1); - depth_first_search(i + 1, j); - depth_first_search(i, j - 1); - } -}; -``` - -# JavaScript -```JavaScript -let grid -let maxArea = 0 -let area - -var maxAreaOfIsland = function (grid_) { - grid = grid_ - maxArea = 0 - - grid.forEach((row, i) => { - row.forEach((value, j) => { - if (value === 1) { - area = 0 - depthFirstSearch(i, j) - maxArea = Math.max(maxArea, area) - } - }) - }) - - return maxArea -}; - - -function depthFirstSearch(i, j) { - if (i < 0 || i >= grid.length) { - return - } - - if (j < 0 || j >= grid[0].length) { - return - } - - if (grid[i][j] != 1) { - return - } - - grid[i][j] = 8 - area++ - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# C# -```c# -public class Solution -{ - int[][] grid; - int maxArea = 0; - int area = 0; - - public int MaxAreaOfIsland(int[][] grid) - { - this.grid = grid; - - for (var i = 0; i < grid.Length; i++) - { - for (var j = 0; j < grid[0].Length; j++) - { - if (grid[i][j] == 1) - { - area = 0; - depthFirstSearch(i, j); - maxArea = Math.Max(maxArea, area); - } - } - } - - return maxArea; - } - - void depthFirstSearch(int i, int j) - { - if (i < 0 || i >= grid.Length) - return; - - if (j < 0 || j >= grid[0].Length) - return; - - if (grid[i][j] != 1) - return; - - grid[i][j] = 8; - area++; - - depthFirstSearch(i - 1, j); - depthFirstSearch(i, j + 1); - depthFirstSearch(i + 1, j); - depthFirstSearch(i, j - 1); - } -} -``` - -# Go -```go -var ( - grid [][]int - maxArea int - area int -) - -func maxAreaOfIsland(grid_ [][]int) int { - grid = grid_ - maxArea = 0 - - for i, row := range grid { - for j, value := range row { - if value == 1 { - area = 0 - depthFirstSearch(i, j) - maxArea = max(maxArea, area) - } - } - } - - return maxArea -} - -func depthFirstSearch(i int, j int) { - if i < 0 || i >= len(grid) { - return - } - - if j < 0 || j >= len(grid[0]) { - return - } - - if grid[i][j] != 1 { - return - } - - grid[i][j] = 8 - area++ - - depthFirstSearch(i - 1, j) - depthFirstSearch(i, j + 1) - depthFirstSearch(i + 1, j) - depthFirstSearch(i, j - 1) -} -``` - -# Ruby -```Ruby -def max_area_of_island(grid) - @grid = grid - @max_area = 0 - @area = 0 - - @grid.each_with_index do |row, i| - row.each_with_index do |value, j| - if value == 1 - @area = 0 - depth_first_search(i, j) - @max_area = [@max_area, @area].max - end - end - end - - @max_area -end - -def depth_first_search(i, j) - return if i < 0 || i >= @grid.size - - return if j < 0 || j >= @grid[0].size - - return if @grid[i][j] != 1 - - @grid[i][j] = 8 - @area += 1 - - depth_first_search(i - 1, j) - depth_first_search(i, j + 1) - depth_first_search(i + 1, j) - depth_first_search(i, j - 1) -end -``` - -# C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -# Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/704-binary-search.md b/zh/1-1000/704-binary-search.md deleted file mode 100644 index 823b84e..0000000 --- a/zh/1-1000/704-binary-search.md +++ /dev/null @@ -1,243 +0,0 @@ -# 704. 二分查找 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[704. 二分查找 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/704-binary-search),体验更佳! - -力扣链接:[704. 二分查找](https://leetcode.cn/problems/binary-search), 难度等级:**简单**。 - -## LeetCode “704. 二分查找”问题描述 - -给定一个 `n` 个元素有序的(升序)整型数组 `nums` 和一个目标值 `target` ,写一个函数搜索 `nums` 中的 `target`,如果目标值存在返回下标,否则返回 `-1`。 - -### [示例 1] - -**输入**: `nums = [-1,0,3,5,9,12], target = 9` - -**输出**: `4` - -**解释**: `9 出现在 `nums` 中并且下标为 4` - -### [示例 2] - -**输入**: `nums = [-1,0,3,5,9,12], target = 2` - -**输出**: `-1` - -**解释**: `2 不存在 `nums` 中因此返回 -1` - -### [约束] - -- 你可以假设 `nums` 中的所有元素是不重复的。 -- `n` 将在 `[1, 10000]` 之间。 -- `nums` 的每个元素都将在 `[-9999, 9999]` 之间。 - -## 思路 - -因为是已经排好序的数组,所以用中间的值进行比较,每次都可以排除掉一半的数字。 - -## 步骤 - -最快、最简单的方法是使用三个索引:`left`、`right` 和 `middle`。 -如果 `nums[middle] > target`,则 `right = middle - 1`,否则 `left = middle + 1`。 - -## 复杂度 - -- 时间复杂度: `O(log N)`. -- 空间复杂度: `O(1)`. - -## Java - -```java -class Solution { - public int search(int[] nums, int target) { - var left = 0; - var right = nums.length - 1; - - while (left <= right) { - var middle = (left + right) / 2; - - if (nums[middle] == target) { - return middle; - } - - if (nums[middle] > target) { - right = middle - 1; - } else { - left = middle + 1; - } - } - - return -1; - } -} -``` - -## Python - -```python -class Solution: - def search(self, nums: List[int], target: int) -> int: - left = 0 - right = len(nums) - 1 - - while left <= right: - middle = (left + right) // 2 - - if nums[middle] == target: - return middle - - if nums[middle] > target: - right = middle - 1 - else: - left = middle + 1 - - return -1 -``` - -## C++ - -```cpp -class Solution { -public: - int search(vector& nums, int target) { - auto left = 0; - int right = nums.size() - 1; // Should not use 'auto' here because 'auto' will make this variable become `unsigned long` which has no `-1`. - - while (left <= right) { - auto middle = (left + right) / 2; - - if (nums[middle] == target) { - return middle; - } - - if (nums[middle] > target) { - right = middle - 1; - } else { - left = middle + 1; - } - } - - return -1; - } -}; -``` - -## JavaScript - -```javascript -var search = function (nums, target) { - let left = 0 - let right = nums.length - 1 - - while (left <= right) { - const middle = Math.floor((left + right) / 2) - - if (nums[middle] == target) { - return middle - } - - if (nums[middle] > target) { - right = middle - 1 - } else { - left = middle + 1 - } - } - - return -1 -}; -``` - -## C# - -```csharp -public class Solution -{ - public int Search(int[] nums, int target) - { - int left = 0; - int right = nums.Length - 1; - - while (left <= right) - { - int middle = (left + right) / 2; - - if (nums[middle] == target) - { - return middle; - } - - if (nums[middle] > target) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return -1; - } -} -``` - -## Go - -```go -func search(nums []int, target int) int { - left := 0 - right := len(nums) - 1 - - for left <= right { - middle := (left + right) / 2 - - if nums[middle] == target { - return middle - } - - if nums[middle] > target { - right = middle - 1 - } else { - left = middle + 1 - } - } - - return -1 -} -``` - -## Ruby - -```ruby -def search(nums, target) - left = 0 - right = nums.size - 1 - - while left <= right - middle = (left + right) / 2 - - return middle if nums[middle] == target - - if nums[middle] > target - right = middle - 1 - else - left = middle + 1 - end - end - - -1 -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[704. 二分查找 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/704-binary-search). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/707-design-linked-list.md b/zh/1-1000/707-design-linked-list.md deleted file mode 100644 index 09fdc8b..0000000 --- a/zh/1-1000/707-design-linked-list.md +++ /dev/null @@ -1,641 +0,0 @@ -# 707. 设计链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[707. 设计链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/707-design-linked-list),体验更佳! - -力扣链接:[707. 设计链表](https://leetcode.cn/problems/design-linked-list), 难度等级:**中等**。 - -## LeetCode “707. 设计链表”问题描述 - -你可以选择使用单链表或者双链表,设计并实现自己的链表。 - -单链表中的节点应该具备两个属性:`val` 和 `next` 。`val` 是当前节点的值,`next` 是指向下一个节点的指针/引用。 - -如果是双向链表,则还需要属性 `prev` 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。 - -实现 `MyLinkedList` 类: - -- `MyLinkedList()` 初始化 `MyLinkedList` 对象。 -- `int get(int index)` 获取链表中下标为 `index` 的节点的值。如果下标无效,则返回 `-1` 。 -- `void addAtHead(int val)` 将一个值为 `val` 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。 -- `void addAtTail(int val)` 将一个值为 `val` 的节点追加到链表中作为链表的最后一个元素。 -- `void addAtIndex(int index, int val)` 将一个值为 `val` 的节点插入到链表中下标为 `index` 的节点之前。如果 `index` 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。 -- `void deleteAtIndex(int index)` 如果下标有效,则删除链表中下标为 `index` 的节点。 - -### [示例 1] - -**输入**: `["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"] [[], [1], [3], [1, 2], [1], [1], [1]]` - -**输出**: `[null, null, null, null, 2, null, 3]` - -**解释**: - -

MyLinkedList myLinkedList = new MyLinkedList();
-myLinkedList.addAtHead(1);
-myLinkedList.addAtTail(3);
-myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
-myLinkedList.get(1); // 返回 2
-myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
-myLinkedList.get(1); // 返回 3

- - -### [约束] - -- `0 <= index, val <= 1000` -- 请不要使用内置的 LinkedList 库。 -- 调用 `get`、`addAtHead`、`addAtTail`、`addAtIndex` 和 `deleteAtIndex` 的次数不超过 `2000` 。 - -## 思路 - -在做本题前,建议先完成较简单的相关题目 [19. 删除链表的倒数第 N 个结点](19-remove-nth-node-from-end-of-list.md)。 - -本题可以全面考察候选人对链表的掌握程度,以下几点需要重视: - -1. 最好使用一个`dummyHead`节点做为链表入口。 -2. 最好使用一个新的`ListNode`类,这样,`dummyHead`就不用和`val`、`next`混在一起。 -3. 先实现容易的方法,顺序为`addAtHead`, `addAtTail`, `addAtIndex`, `deleteAtIndex`, `get`。 - -## 复杂度 - -- 时间复杂度: `O(N * N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class ListNode { - int val; - ListNode next; - - ListNode(int val) { - this.val = val; - } -} - -class MyLinkedList { - private ListNode dummyHead = new ListNode(0); - - public MyLinkedList() {} - - public int get(int index) { - var node = dummyHead.next; - var i = 0; - - while (node != null && i < index) { - node = node.next; - i += 1; - } - - if (i == index && node != null) { - return node.val; - } - - return -1; - } - - public void addAtHead(int val) { - var node = new ListNode(val); - node.next = dummyHead.next; - dummyHead.next = node; - } - - public void addAtTail(int val) { - var node = dummyHead; - - while (node.next != null) { - node = node.next; - } - - node.next = new ListNode(val); - } - - public void addAtIndex(int index, int val) { - var node = dummyHead; - var i = 0; - - while (node.next != null && i < index) { - node = node.next; - i += 1; - } - - if (i == index) { - var newNode = new ListNode(val); - newNode.next = node.next; - node.next = newNode; - } - } - - public void deleteAtIndex(int index) { - var node = dummyHead; - var i = 0; - - while (node.next != null && i < index) { - node = node.next; - i += 1; - } - - if (i == index && node.next != null) { - node.next = node.next.next; - } - } -} -``` - -## Python - -```python -class ListNode: - def __init__(self, val=None): - self.val = val - self.next = None - - -class MyLinkedList: - def __init__(self): - self.dummy_head = ListNode() - - def get(self, index: int) -> int: - node = self.dummy_head.next - i = 0 - - while node and i < index: - node = node.next - i += 1 - - if i == index and node: - return node.val - - return -1 - - def addAtHead(self, val: int) -> None: - node = ListNode(val) - node.next = self.dummy_head.next - self.dummy_head.next = node - - def addAtTail(self, val: int) -> None: - node = self.dummy_head - - while node.next: - node = node.next - - node.next = ListNode(val) - - def addAtIndex(self, index: int, val: int) -> None: - node = self.dummy_head - i = 0 - - while node.next and i < index: - node = node.next - i += 1 - - if i == index: - new_node = ListNode(val) - new_node.next = node.next - node.next = new_node - - def deleteAtIndex(self, index: int) -> None: - node = self.dummy_head - i = 0 - - while node.next and i < index: - node = node.next - i += 1 - - if i == index and node.next: - node.next = node.next.next -``` - -## JavaScript - -```javascript -class ListNode { - constructor(val) { - this.val = val - this.next = null - } -} - -var MyLinkedList = function () { - this.dummyHead = new ListNode(0) -}; - -MyLinkedList.prototype.get = function (index) { - let node = this.dummyHead.next - let i = 0 - - while (node != null && i < index) { - node = node.next - i += 1 - } - - if (i == index && node != null) { - return node.val - } - - return -1 -}; - -MyLinkedList.prototype.addAtHead = function (val) { - const node = new ListNode(val) - node.next = this.dummyHead.next - this.dummyHead.next = node -}; - -MyLinkedList.prototype.addAtTail = function (val) { - let node = this.dummyHead - - while (node.next != null) { - node = node.next - } - - node.next = new ListNode(val) -}; - -MyLinkedList.prototype.addAtIndex = function (index, val) { - let node = this.dummyHead - let i = 0 - - while (node.next != null && i < index) { - node = node.next - i += 1 - } - - if (i == index) { - const newNode = new ListNode(val); - newNode.next = node.next; - node.next = newNode; - } -}; - -MyLinkedList.prototype.deleteAtIndex = function (index) { - let node = this.dummyHead - let i = 0 - - while (node.next != null && i < index) { - node = node.next - i += 1 - } - - if (i == index && node.next != null) { - node.next = node.next.next - } -}; -``` - -## C# - -```csharp -public class ListNode -{ - public int val; - public ListNode next; - - public ListNode(int val) - { - this.val = val; - } -} - -public class MyLinkedList -{ - ListNode dummyHead = new ListNode(0); - - public MyLinkedList() {} - - public int Get(int index) - { - var node = dummyHead.next; - int i = 0; - - while (node != null && i < index) - { - node = node.next; - i += 1; - } - - if (i == index && node != null) - return node.val; - - return -1; - } - - public void AddAtHead(int val) - { - var node = new ListNode(val); - node.next = dummyHead.next; - dummyHead.next = node; - } - - public void AddAtTail(int val) - { - var node = dummyHead; - - while (node.next != null) - node = node.next; - - node.next = new ListNode(val); - } - - public void AddAtIndex(int index, int val) - { - var node = dummyHead; - int i = 0; - - while (node.next != null && i < index) - { - node = node.next; - i += 1; - } - - if (i == index) { - var newNode = new ListNode(val); - newNode.next = node.next; - node.next = newNode; - } - } - - public void DeleteAtIndex(int index) - { - var node = dummyHead; - int i = 0; - - while (node.next != null && i < index) - { - node = node.next; - i += 1; - } - - if (i == index && node.next != null) - node.next = node.next.next; - } -} -``` - -## Go - -```go -// ListNode represents a node in the singly-linked list -// type ListNode struct { -// Val int -// Next *ListNode -// } - -// MyLinkedList implements linked list operations using a dummy head node -type MyLinkedList struct { - dummyHead *ListNode -} - -// Constructor initializes a new linked list -func Constructor() MyLinkedList { - return MyLinkedList{ - dummyHead: &ListNode{}, // Initialize dummy head with zero value - } -} - -// Get retrieves the value at specified index, returns -1 for invalid indices -func (ll *MyLinkedList) Get(index int) int { - current := ll.dummyHead.Next - count := 0 - - // Traverse until reaching desired index or end of list - for current != nil && count < index { - current = current.Next - count++ - } - - // Validate index and return value if found - if current != nil && count == index { - return current.Val - } - return -1 -} - -// AddAtHead inserts new node at beginning of the list -func (ll *MyLinkedList) AddAtHead(val int) { - newNode := &ListNode{Val: val} - newNode.Next = ll.dummyHead.Next - ll.dummyHead.Next = newNode -} - -// AddAtTail appends new node at end of the list -func (ll *MyLinkedList) AddAtTail(val int) { - current := ll.dummyHead - // Traverse to last node - for current.Next != nil { - current = current.Next - } - current.Next = &ListNode{Val: val} -} - -// AddAtIndex inserts node at specified position if valid -func (ll *MyLinkedList) AddAtIndex(index int, val int) { - prev := ll.dummyHead - count := 0 - - // Find insertion point - for prev.Next != nil && count < index { - prev = prev.Next - count++ - } - - // Only insert if index matches traversal count - if count == index { - newNode := &ListNode{Val: val} - newNode.Next = prev.Next - prev.Next = newNode - } -} - -// DeleteAtIndex removes node at specified position if valid -func (ll *MyLinkedList) DeleteAtIndex(index int) { - prev := ll.dummyHead - count := 0 - - // Find node preceding the deletion target - for prev.Next != nil && count < index { - prev = prev.Next - count++ - } - - // Perform deletion if index is valid and node exists - if prev.Next != nil && count == index { - prev.Next = prev.Next.Next - } -} -``` - -## C++ - -```cpp -class MyLinkedList { -private: - struct ListNode { - int val; - ListNode* next; - ListNode(int x) : val(x), next(nullptr) {} - }; - - ListNode* dummy_head_; - -public: - MyLinkedList() { - dummy_head_ = new ListNode(0); - } - - int get(int index) { - auto node = dummy_head_->next; - auto i = 0; - - while (node && i < index) { - node = node->next; - i++; - } - - return (i == index && node) ? node->val : -1; - } - - void addAtHead(int val) { - auto node = new ListNode(val); - node->next = dummy_head_->next; - dummy_head_->next = node; - } - - void addAtTail(int val) { - auto node = dummy_head_; - while (node->next) { - node = node->next; - } - node->next = new ListNode(val); - } - - void addAtIndex(int index, int val) { - auto node = dummy_head_; - auto i = 0; - - while (node->next && i < index) { - node = node->next; - i++; - } - - if (i == index) { - auto new_node = new ListNode(val); - new_node->next = node->next; - node->next = new_node; - } - } - - void deleteAtIndex(int index) { - auto node = dummy_head_; - auto i = 0; - - while (node->next && i < index) { - node = node->next; - i++; - } - - if (i == index && node->next) { - auto to_delete = node->next; - node->next = node->next->next; - delete to_delete; - } - } -}; - -``` - -## Ruby - -```ruby -# ListNode class with val and next_node (since 'next' is reserved in some languages) -class ListNode - attr_accessor :val, :next_node - - def initialize(val = nil) - @val = val - @next_node = nil - end -end - -# MyLinkedList implementation with dummy head -class MyLinkedList - def initialize - @dummy_head = ListNode.new # Dummy head node - end - - # Get value at index, return -1 if invalid - def get(index) - current = @dummy_head.next_node - count = 0 - - while current && count < index - current = current.next_node - count += 1 - end - - current && count == index ? current.val : -1 - end - - # Add node at head - def add_at_head(val) - new_node = ListNode.new(val) - new_node.next_node = @dummy_head.next_node - @dummy_head.next_node = new_node - end - - # Add node at tail - def add_at_tail(val) - current = @dummy_head - - while current.next_node - current = current.next_node - end - - current.next_node = ListNode.new(val) - end - - # Add node at index if valid - def add_at_index(index, val) - prev = @dummy_head - count = 0 - - while prev.next_node && count < index - prev = prev.next_node - count += 1 - end - - if count == index - new_node = ListNode.new(val) - new_node.next_node = prev.next_node - prev.next_node = new_node - end - end - - # Delete node at index if valid - def delete_at_index(index) - prev = @dummy_head - count = 0 - - while prev.next_node && count < index - prev = prev.next_node - count += 1 - end - - if prev.next_node && count == index - prev.next_node = prev.next_node.next_node - end - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[707. 设计链表 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/707-design-linked-list). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md b/zh/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md deleted file mode 100644 index 8f6c38f..0000000 --- a/zh/1-1000/714-best-time-to-buy-and-sell-stock-with-transaction-fee.md +++ /dev/null @@ -1,132 +0,0 @@ -# 714. Best Time to Buy and Sell Stock with Transaction Fee -LeetCode link: [714. Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) - -## LeetCode problem description -You are given an array `prices` where `prices[i]` is the price of a given stock on the `i-th` day, and an integer `fee` representing a transaction fee. - -Find the **maximum profit** you can achieve. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. - -**Note:** - -* You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). -* The transaction fee is only charged once for each stock purchase and sale. - -``` ------------------------------------------------------------------- -[Example 1] - -Input: prices = [1,3,2,8,4,9], fee = 2 -Output: 8 - -Explanation: The maximum profit can be achieved by: -- Buying at prices[0] = 1 -- Selling at prices[3] = 8 -- Buying at prices[4] = 4 -- Selling at prices[5] = 9 -The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8. ------------------------------------------------------------------- -[Example 2] - -Input: prices = [1,3,7,5,10,3], fee = 3 -Output: 6 ------------------------------------------------------------------- -[Constraints] - -1 <= prices.length <= 5 * 10000 -1 <= prices[i] < 5 * 10000 -0 <= fee < 5 * 10000 ------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 3 to 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def maxProfit(self, prices: List[int], fee: int) -> int: - # states: - # 0: hold stock - # 1) keep holding - # 2) today just bought - # 1: no stock - # 1) keep no stock - # 2) today just sold - dp = [-prices[0], 0] - - for price in prices[1:]: - dc = dp.copy() - - dp[0] = max(dc[0], dc[1] - price) - dp[1] = max(dc[1], dc[0] + price - fee) - - return dp[1] -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var maxProfit = function (prices, fee) { - const dp = [-prices[0], 0] - - for (let i = 1; i < prices.length; i++) { - const dc = [...dp] - - dp[0] = Math.max(dc[0], dc[1] - prices[i]) - dp[1] = Math.max(dc[1], dc[0] + prices[i] - fee) - } - - return dp[1] -}; -``` - -## Go -```go -func maxProfit(prices []int, fee int) int { - dp := []int{-prices[0], 0} - - for i := 1; i < len(prices); i++ { - dc := slices.Clone(dp) - - dp[0] = max(dc[0], dc[1] - prices[i]) - dp[1] = max(dc[1], dc[0] + prices[i] - fee) - } - - return dp[1] -} -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/718-maximum-length-of-repeated-subarray.md b/zh/1-1000/718-maximum-length-of-repeated-subarray.md deleted file mode 100644 index a079ccb..0000000 --- a/zh/1-1000/718-maximum-length-of-repeated-subarray.md +++ /dev/null @@ -1,148 +0,0 @@ -# 718. Maximum Length of Repeated Subarray -LeetCode link: [718. Maximum Length of Repeated Subarray](https://leetcode.com/problems/maximum-length-of-repeated-subarray/) - -## LeetCode problem description -Given two integer arrays `nums1` and `nums2`, return the **maximum length of a subarray** that appears in **both** arrays. - -``` ------------------------------------------------------------------------- -[Example 1] - -Input: nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] -Output: 3 - -Explanation: The repeated subarray with maximum length is [3,2,1]. ------------------------------------------------------------------------- -[Example 2] - -Input: nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0] -Output: 5 - -Explanation: The repeated subarray with maximum length is [0,0,0,0,0]. ------------------------------------------------------------------------- -[Constraints] - -1 <= nums1.length, nums2.length <= 1000 -0 <= nums1[i], nums2[i] <= 100 ------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 4 to 7 languages are given. - -**Do not use a rolling array** as `dp` because that is more difficult to write and understand. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Java -```java -class Solution { - public int findLength(int[] nums1, int[] nums2) { - var maxLength = 0; - var dp = new int[nums1.length + 1][nums2.length + 1]; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - maxLength = Math.max(dp[i][j], maxLength); - } - } - } - - return maxLength; - } -} -``` - -## C# -```c# -public class Solution -{ - public int FindLength(int[] nums1, int[] nums2) - { - int maxLength = 0; - var dp = new int[nums1.Length + 1, nums2.Length + 1]; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (nums1[i - 1] == nums2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1] + 1; - maxLength = Math.Max(dp[i, j], maxLength); - } - } - } - - return maxLength; - } -} -``` - -## Python -```python -class Solution: - def findLength(self, nums1: List[int], nums2: List[int]) -> int: - max_length = 0 - dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if nums1[i - 1] == nums2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - max_length = max(dp[i][j], max_length) - - return max_length -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -var findLength = function (nums1, nums2) { - let maxLength = 0 - const dp = Array(nums1.length + 1).fill().map( - () => Array(nums2.length + 1).fill(0) - ) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - maxLength = Math.max(dp[i][j], maxLength) - } - } - } - - return maxLength -}; -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/72-edit-distance.md b/zh/1-1000/72-edit-distance.md deleted file mode 100644 index 2d833a4..0000000 --- a/zh/1-1000/72-edit-distance.md +++ /dev/null @@ -1,383 +0,0 @@ -# 72. 编辑距离 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[72. 编辑距离 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/72-edit-distance),体验更佳! - -力扣链接:[72. 编辑距离](https://leetcode.cn/problems/edit-distance), 难度等级:**中等**。 - -## LeetCode “72. 编辑距离”问题描述 - -给你两个单词 `word1` 和 `word2`, 请返回将 `word1` 转换成 `word2` 所使用的**最少操作数**。 - -你可以对一个单词进行如下三种操作: - -- 插入一个字符 -- 删除一个字符 -- 替换一个字符 - -### [示例 1] - -**输入**: `word1 = "horse", word2 = "ros"` - -**输出**: `3` - -**解释**: - -

horse -> rorse (将 'h' 替换为 'r')
-rorse -> rose (删除 'r')
-rose -> ros (删除 'e')

- - -### [示例 2] - -**输入**: `word1 = "intention", word2 = "execution"` - -**输出**: `5` - -**解释**: - -

intention -> inention (删除 't')
-inention -> enention (将 'i' 替换为 'e')
-enention -> exention (将 'n' 替换为 'x')
-exention -> exection (将 'n' 替换为 'c')
-exection -> execution (插入 'u')

- - -### [约束] - -1. `0 <= word1.length, word2.length <= 500` -2. `word1` 和 `word2` 由小写英文字母组成 - -## 思路 - -这是一道比较两个字符串的题目。在多次练习类似的题目之后,我们能培养出使用*二维*数组`dp`的“动态规划”方法解决本问题的直觉。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## “子序列问题”的模式 - -- 由于要比较有两个可互换位置的数组(或字符串),我们使用**二维**数组作为`dp`。 -- `dp` 数组的遍历顺序是从上到下,然后从左到右。 - -## 步骤 - -1. 确定数组`dp`的每个值代表的**含义**。 - - `dp[i][j]` 表示将 `word1` 的前 `i` 个字母转换为 `word2` 的前 `j` 个字母所需的**最小**操作次数。 - - `dp[i][j]` 是一个整数。 -2. 初始化数组`dp`的值。 - - 使用示例: - - ``` - 初始化后,dp 数组应为: - # r o s - # 0 1 2 3 # dp[0] - # h 1 0 0 0 - # o 2 0 0 0 - # r 3 0 0 0 - # s 4 0 0 0 - # e 5 0 0 0 - ``` - - `dp[i][0] = i`,因为`dp[i][0]`表示空字符串,操作次数就是需要删除的字符数。 - - `dp[0][j] = j`,原因与上一行相同,只是角度相反:将`word2`转换为`word1`。 - -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - ``` - 1. 将`h`转换为`ros`。 - # r o s - # 0 1 2 3 - # h 1 1 2 3 # dp[1] - ``` - ``` - 2. 将`ho`转换为`ros`。 - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - ``` - ``` - 3. 将`hor`转换为`ros`。 - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - # r 3 2 2 2 - ``` - ``` - 4. 将`hors`转换为`ros`。 - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - # r 3 2 2 2 - # s 4 3 3 2 - ``` - ``` - 5. 将 `horse` 转换为 `ros`。 - # r o s - # 0 1 2 3 - # h 1 1 2 3 - # o 2 2 1 2 - # r 3 2 2 2 - # s 4 3 3 2 - # e 5 4 4 3 # dp[5] - ``` -4. 根据`dp`网格数据,推导出**递推公式**。 - - ```python - if word1[i - 1] == word2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min( - dp[i - 1][j - 1], - dp[i - 1][j], - dp[i][j - 1], - ) + 1 - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 复杂度 - -- 时间复杂度: `O(N * M)`. -- 空间复杂度: `O(N * M)`. - -## Java - -```java -class Solution { - public int minDistance(String word1, String word2) { - var dp = new int[word1.length() + 1][word2.length() + 1]; - for (var i = 0; i < dp.length; i++) { - dp[i][0] = i; - } - for (var j = 0; j < dp[0].length; j++) { - dp[0][j] = j; - } - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (word1.charAt(i - 1) == word2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1; - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public int MinDistance(string word1, string word2) - { - var dp = new int[word1.Length + 1, word2.Length + 1]; - - for (var i = 0; i < dp.GetLength(0); i++) - dp[i, 0] = i; - - for (var j = 0; j < dp.GetLength(1); j++) - dp[0, j] = j; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (word1[i - 1] == word2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1]; - } - else - { - dp[i, j] = Math.Min(dp[i - 1, j - 1], Math.Min(dp[i - 1, j], dp[i, j - 1])) + 1; - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Python - -```python -class Solution: - def minDistance(self, word1: str, word2: str) -> int: - dp = [[0] * (len(word2) + 1) for _ in range(len(word1) + 1)] - for i in range(len(dp)): - dp[i][0] = i - for j in range(len(dp[0])): - dp[0][j] = j - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if word1[i - 1] == word2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 - - return dp[-1][-1] -``` - -## C++ - -```cpp -class Solution { -public: - int minDistance(string word1, string word2) { - vector> dp(word1.size() + 1, vector(word2.size() + 1)); - for (auto i = 0; i < dp.size(); i++) { - dp[i][0] = i; - } - for (auto j = 0; j < dp[0].size(); j++) { - dp[0][j] = j; - } - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1; - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript - -```javascript -var minDistance = function (word1, word2) { - const dp = Array(word1.length + 1).fill().map( - () => Array(word2.length + 1).fill(0) - ) - dp.forEach((_, i) => { dp[i][0] = i }) - dp[0].forEach((_, j) => { dp[0][j] = j }) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (word1[i - 1] == word2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go - -```go -func minDistance(word1 string, word2 string) int { - dp := make([][]int, len(word1) + 1) - for i := range dp { - dp[i] = make([]int, len(word2) + 1) - dp[i][0] = i - } - for j := range dp[0] { - dp[0][j] = j - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if word1[i - 1] == word2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] - } else { - dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby - -```ruby -def min_distance(word1, word2) - dp = Array.new(word1.size + 1) do - Array.new(word2.size + 1, 0) - end - dp.each_with_index do |_, i| - dp[i][0] = i - end - dp[0].each_with_index do |_, j| - dp[0][j] = j - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if word1[i - 1] == word2[j - 1] - dp[i - 1][j - 1] - else - [ dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1] ].min + 1 - end - end - end - - dp[-1][-1] -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[72. 编辑距离 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/72-edit-distance). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/739-daily-temperatures.md b/zh/1-1000/739-daily-temperatures.md deleted file mode 100644 index 511cdc7..0000000 --- a/zh/1-1000/739-daily-temperatures.md +++ /dev/null @@ -1,217 +0,0 @@ -# 739. Daily Temperatures -LeetCode link: [739. Daily Temperatures](https://leetcode.com/problems/daily-temperatures/) - -## LeetCode problem description -Given an array of integers `temperatures` represents the daily temperatures, return an array `answer` such that `answer[i]` is the number of days you have to wait after the `i-th` day to get a warmer temperature. If there is no future day for which this is possible, keep `answer[i] == 0` instead. - -``` ------------------------------------------------------------------------- -[Example 1] - -Input: temperatures = [73,74,75,71,69,72,76,73] -Output: [1,1,4,2,1,1,0,0] ------------------------------------------------------------------------- -[Example 2] - -Input: temperatures = [30,40,50,60] -Output: [1,1,1,0] ------------------------------------------------------------------------- -[Example 3] - -Input: temperatures = [30,60,90] -Output: [1,1,0] ------------------------------------------------------------------------- -[Constraints] - -1 <= temperatures.length <= 100000 -30 <= temperatures[i] <= 100 ------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Java -```java -class Solution { - public int[] dailyTemperatures(int[] temperatures) { - var results = new int[temperatures.length]; - var indexStack = new Stack(); - - for (var i = 0; i < temperatures.length; i++) { - while (!indexStack.empty() && temperatures[indexStack.peek()] < temperatures[i]) { - var index = indexStack.pop(); - results[index] = i - index; - } - - indexStack.push(i); - } - - return results; - } -} -``` - -## Python -```python -class Solution: - def dailyTemperatures(self, temperatures: List[int]) -> List[int]: - results = [0] * len(temperatures) - index_stack = [] - - for i, temperature in enumerate(temperatures): - while index_stack and temperature > temperatures[index_stack[-1]]: - index = index_stack.pop() - results[index] = i - index - - index_stack.append(i) - - return results -``` - -## C++ -```cpp -class Solution { -public: - vector dailyTemperatures(vector& temperatures) { - vector results(temperatures.size()); - stack index_stack; - - for (auto i = 0; i < temperatures.size(); i++) { - while (!index_stack.empty() && temperatures[i] > temperatures[index_stack.top()]) { - results[index_stack.top()] = i - index_stack.top(); - index_stack.pop(); - } - - index_stack.push(i); - } - - return results; - } -}; -``` - -## JavaScript -```javascript -var dailyTemperatures = function (temperatures) { - const results = Array(temperatures.length).fill(0) - const indexStack = [] - - temperatures.forEach((temperature, i) => { - while (indexStack.length > 0 && temperatures[indexStack.at(-1)] < temperature) { - results[indexStack.at(-1)] = i - indexStack.at(-1) - indexStack.pop() - } - - indexStack.push(i) - }) - - return results -}; -``` - -## C# -```c# -public class Solution -{ - public int[] DailyTemperatures(int[] temperatures) - { - var results = new int[temperatures.Length]; - var indexStack = new Stack(); - - for (var i = 0; i < temperatures.Length; i++) - { - while (indexStack.Count > 0 && temperatures[indexStack.Peek()] < temperatures[i]) - { - int index = indexStack.Pop(); - results[index] = i - index; - } - - indexStack.Push(i); - } - - return results; - } -} -``` - -## Go -### Solution 1: Using a 'slice' as stack -```go -func dailyTemperatures(temperatures []int) []int { - results := make([]int, len(temperatures)) - indexStack := []int{} - - for i, temperature := range temperatures { - for len(indexStack) > 0 && temperature > temperatures[indexStack[len(indexStack) - 1]] { - index := indexStack[len(indexStack) - 1] - results[index] = i - index - indexStack = indexStack[:len(indexStack) - 1] - } - - indexStack = append(indexStack, i) - } - - return results -} -``` - -### Solution 2: Using `GoDS` stack -```go -func dailyTemperatures(temperatures []int) []int { - results := make([]int, len(temperatures)) - indexStack := arraystack.New() - - for i, temperature := range temperatures { - for !indexStack.Empty() { - index, _ := indexStack.Peek(); - - if temperature <= temperatures[index.(int)] { - break - } - - indexStack.Pop() - results[index.(int)] = i - index.(int) - } - - indexStack.Push(i) - } - - return results -} -``` - -## Ruby -```ruby -def daily_temperatures(temperatures) - results = Array.new(temperatures.size, 0) - index_stack = [] - - temperatures.each_with_index do |temperature, i| - while !index_stack.empty? && temperatures[index_stack.last] < temperature - results[index_stack.last] = i - index_stack.last - index_stack.pop - end - - index_stack << i - end - - results -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/743-network-delay-time.md b/zh/1-1000/743-network-delay-time.md deleted file mode 100644 index aa9f664..0000000 --- a/zh/1-1000/743-network-delay-time.md +++ /dev/null @@ -1,294 +0,0 @@ -# 743. 网络延迟时间 - 力扣题解最佳实践 -力扣链接:[743. 网络延迟时间](https://leetcode.cn/problems/network-delay-time) ,难度:**中等**。 - -## 力扣“743. 网络延迟时间”问题描述 -有 `n` 个网络节点,标记为 `1` 到 `n`。 - -给你一个列表 `times`,表示信号经过 **有向** 边的传递时间。 `times[i] = (ui, vi, wi)`,其中 `ui` 是源节点,`vi` 是目标节点, `wi` 是一个信号从源节点传递到目标节点的时间。 - -现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 `-1` 。 - -### [示例 1] -![](../../images/examples/743_1.png) - -**输入**: `times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2` - -**输出**: `2` - -### [示例 2] -**输入**: `times = [[1,2,1]], n = 2, k = 1` - -**输出**: `1` - -### [示例 3] -**输入**: `times = [[1,2,1]], n = 2, k = 2` - -**输出**: `-1` - -### [约束] -- `1 <= k <= n <= 100` -- `1 <= times.length <= 6000` -- `times[i].length == 3` -- `1 <= ui, vi <= n` -- `ui != vi` -- `0 <= wi <= 100` -- 所有 `(ui, vi)` 对都 **互不相同**(即,不含重复边) - -### [提示] -
- 提示 1 - We visit each node at some time, and if that time is better than the fastest time we've reached this node, we travel along outgoing edges in sorted order. Alternatively, we could use Dijkstra's algorithm. -
- -## 思路 -本题可用 **Bellman-Ford算法** 或 **Dijkstra算法** 解决。 - -### Bellman-Ford算法 -*Bellman-Ford算法*的动画演示: - -![](../../images/graph_Bellman-Ford_algorithm_animation.gif) - -* `Bellman-Ford`算法代码量少,还能处理`边`权值为**负数**的情况,但如果没有被优化过,运行得比较慢。下文代码会介绍如何优化。 - -* `Dijkstra算法`因为始终走最短路径,所以执行**效率高**!但代码量大,无法处理`边`权值为**负数**的情况。 - -**Dijkstra算法**的详细说明,请参考 [1514. 概率最大的路径](../1001-2000/1514-path-with-maximum-probability.md)。 - -### 常见图论算法对照表 - -|算法名称|主要的适用场景|优化方式|重要度|难度|min_
distances|负边权值|额外的适用场景| -|-------|-----------|-------|-------|---|-------------|--------|------------| -|[深度优先搜索](./797-all-paths-from-source-to-target.md) |遍历图 |无需优化 |很重要 |简单|不用|能处理|| -|[广度优先搜索](../1001-2000/1971-find-if-path-exists-in-graph.md) |遍历图 |无需优化 |很重要 |简单|不用|能处理|不考虑权时,可用于求单源最短路径| -|[并查集](./684-redundant-connection.md) |检测图的连通性|路径压缩|很重要 |中等|不用|能处理|[有向图环检测](./685-redundant-connection-ii.md)| -|[Prim 算法](../1001-2000/1584-min-cost-to-connect-all-points.md) |最小生成树 |堆排序简化|重要 |中等|用到|能处理|| -|[Kruskal 算法](../1001-2000/1584-min-cost-to-connect-all-points-2.md) |最小生成树 |无需优化 |重要 |较难|不用|能处理|| -|[Dijkstra 算法](../1001-2000/1514-path-with-maximum-probability.md) |单源最短路径|堆排序优化|很重要 |较难|用到|无能力|| -|[A* 算法](./752-open-the-lock.md) |单源最短路径|固有堆排序|很重要 |中等|不用|看情况|| -|[Bellman-Ford](./743-network-delay-time.md) |单源最短路径|集合优化 |很重要 |简单|用到|能处理|[负环检测](https://www.geeksforgeeks.org/detect-negative-cycle-graph-bellman-ford/), [限定步数最短路径](./787-cheapest-flights-within-k-stops.md)| -|[Floyd–Warshall](../1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md)|多源最短路径|无需优化 |较不重要|较难|用到|能处理|| - -## 复杂度 -**V**: 顶点数量,**E**: 边的数量。 - -### Bellman-Ford 算法 -* 时间: `O(V * E)`. -* 空间: `O(V)`. - -### 列队(或集合)优化的 Bellman-Ford 算法 (又称 `最短路径快速算法`,缩写为 `SPFA`) -* Time: `O(V * X)` (`X` < `E`). -* Space: `O(V + E)`. - -### Dijkstra 算法(采用`堆排序`) -* 时间: `O(E * log(E))`. -* 空间: `O(V + E)`. - -## Python -### Bellman-Ford 算法(较慢,后文介绍如何性能提升) -一个与本题非常类似的题目: [787. K 站中转内最便宜的航班](./787-cheapest-flights-within-k-stops.md), 然而,如果你用上面同样的代码,会无法通过力扣测试。 - -你可以先尝试解决`787. K 站中转内最便宜的航班`,然后再继续阅读下文。 - -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - - for _ in range(n - 1): - # 删除这一行,始终用`min_times`,也能通过,但`787. K 站中转内最便宜的航班` https://leetcode.cn/problems/cheapest-flights-within-k-stops/ 就通过不了了。 - # 如果你打印`min_times`,很可能会发现结果不一样。请尝试下。 - # 原因就是本轮循环中修改了的`min_times`的值,有可能在本轮循环中被使用到,对本轮后续的`min_times`产生影响。 - # 为更好地理解本行代码,请做 `787. K 站中转内最便宜的航班`。 - min_times_clone = min_times.copy() # addition 1 - - for source_node, target_node, time in edges: # process edges directly - if min_times_clone[source_node] == float('inf'): # change 1 - continue - - target_time = time + min_times_clone[source_node] # change 2 - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### Bellman-Ford 算法的变体,可用于后文的性能提升 -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - - for source, target, time in edges: # process nodes first, then their edges - node_to_pairs[source].add((target, time)) - - for _ in range(n - 1): - for node, min_time in enumerate(min_times): # process nodes first - if min_time == float('inf'): - continue - - for target_node, time in node_to_pairs[node]: # process edges of the node - target_time = time + min_time - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### 列队(或集合)优化的 Bellman-Ford 算法 (Queue-improved Bellman-Ford) -又称 `最短路径快速算法` (`Shortest Path Faster Algorithm` 缩写为 `SPFA`)。 -```python -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - - for source, target, time in edges: # process nodes first, then their edges - node_to_pairs[source].add((target, time)) - - updated_nodes = set([start_node]) # added 1 - - for _ in range(n - 1): - nodes = updated_nodes.copy() # added 3 - updated_nodes.clear() # added 4 - - for node in nodes: # changed 1 - for target_node, time in node_to_pairs[node]: # process edges of the node - target_time = time + min_times[node] - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - updated_nodes.add(target_node) # added 2 - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### Dijkstra's algorithm using `heap sort` (without `visited`) -```python -import heapq - -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - - for source, target, time in edges: - node_to_pairs[source].add((target, time)) - - priority_queue = [(0, start_node)] - - while priority_queue: - current_time, current_node = heapq.heappop(priority_queue) - - for target_node, time in node_to_pairs[current_node]: - target_time = time + current_time - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - heapq.heappush(priority_queue, (target_time, target_node)) - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -### Dijkstra's algorithm using `heap sort` (with `visited`) -```python -import heapq - -class Solution: - def networkDelayTime(self, edges: List[List[int]], n: int, start_node: int) -> int: - min_times = [float('inf')] * (n + 1) - min_times[start_node] = 0 - node_to_pairs = defaultdict(set) - visited = [False] * (n + 1) # added 1 - - for source, target, time in edges: - node_to_pairs[source].add((target, time)) - - priority_queue = [(0, start_node)] - - while priority_queue: - current_time, current_node = heapq.heappop(priority_queue) - - if visited[current_node]: # added 3 - continue - - visited[current_node] = True # added 2 - - for target_node, time in node_to_pairs[current_node]: - if visited[target_node]: # added 4 - continue - - target_time = time + current_time - - if target_time < min_times[target_node]: - min_times[target_node] = target_time - heapq.heappush(priority_queue, (target_time, target_node)) - - result = max(min_times[1:]) - - if result == float('inf'): - return -1 - - return result -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/752-open-the-lock.md b/zh/1-1000/752-open-the-lock.md deleted file mode 100644 index 5ae4586..0000000 --- a/zh/1-1000/752-open-the-lock.md +++ /dev/null @@ -1,240 +0,0 @@ -# 752. 打开转盘锁 - 力扣题解最佳实践 -力扣链接:[752. 打开转盘锁](https://leetcode.cn/problems/open-the-lock) ,难度:**中等**。 - -## 力扣“752. 打开转盘锁”问题描述 -你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: `'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'` 。每个拨轮可以自由旋转:例如把 `9` 变为 `0`,`0` 变为 `9` 。每次旋转都只能旋转一个拨轮的一位数字。 - -锁的初始数字为 `'0000'` ,一个代表四个拨轮的数字的字符串。 - -列表 `deadends` 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。 - -字符串 `target` 代表可以解锁的数字,你需要给出*解锁需要的**最小**旋转次数*,如果无论如何不能解锁,返回 `-1` 。 - -### [示例 1] -**输入**: `deadends = ["0201","0101","0102","1212","2002"], target = "0202"` - -**输出**: `6` - -**解释**: -``` -可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。 -注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的, -因为当拨动到 "0102" 时这个锁就会被锁定。 -``` - -### [示例 2] -**输入**: `deadends = ["8888"], target = "0009"` - -**输出**: `1` - -**解释**: `把最后一位反向旋转一次即可 "0000" -> "0009"。` - -### [示例 3] -**输入**: `["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"` - -**输出**: `-1` - -**解释**: `无法旋转到目标数字且不被锁定。` - -### [约束] -- `1 <= deadends.length <= 500` -- `deadends[i].length == 4` -- `target.length == 4` -- `target` **不在** `deadends` 之中 -- `target` 和 `deadends[i]` 仅由若干位数字组成 - -### [提示] -
- 提示 1 - We can think of this problem as a shortest path problem on a graph: there are `10000` nodes (strings `'0000'` to `'9999'`), and there is an edge between two nodes if they differ in one digit, that digit differs by 1 (wrapping around, so `'0'` and `'9'` differ by 1), and if *both* nodes are not in `deadends`. -
- -## 思路 -我们可以把这个问题想像为一个`求无向图的最短路径`问题。 - -`图`中最多有`10000`个顶点,从顶点`'0000'`到顶点`'9999'`,但`deadends`代表的顶点要从图中移除。如果两个顶点只相差一个数字,那么它们之间有一条边。 - -### 题解 1: 广度优先搜索 -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **Breadth-First Search** can be thought of as visiting vertices in rounds and rounds. Actually, whenever you see a question is about - getting `minimum number` of something of a graph, `Breadth-First Search` would probably help. - -* `Breadth-First Search` emphasizes first-in-first-out, so a **queue** is needed. - -### 题解 2: A* (A-Star) 算法 - -重头戏来了! - -`A* (A-Star) 算法` 可以用于极大提升 `广度优先搜索` 的性能。 - -`广度优先搜索` 对每一个顶点都同等对待,这样难免性能会差。 - -`A* (A-Star) 算法` 会对每一个`顶点`与`目标顶点`的**距离**进行计算,**距离近的顶点优先处理**,相当于为下一步处理哪个顶点指明了方向,因此性能有很大的提升! - -`A* (A-Star) 算法` 和 `Dijkstra's 算法` 比较像,但`A* 算法`的`目标顶点`是明确的,但`Dijkstra's 算法`不明确。`Dijkstra's 算法`是走到哪个顶点就计算从`起点`到`那个顶点`的距离。 - -#### A* (A-Star) 算法的两(三)个关键动作 -1. 要用 `priority_queue`。 -2. 计算距离的`启发式函数`要**精心设计**。设计不好,将导致不易察觉的结果错误! -3. 在特殊情况下,单纯地用`距离`作为`priority_queue`的排序依据还不够,还要**调整一下**(比如与`步数`变量值相加),以使最后几步能精确(本例子不涉及,但这个例子 [1197. Minimum Knight Moves](https://leetcode.com/problems/minimum-knight-moves/) 涉及)。 - -## 复杂度 -> `N` 是 `deadends.length`. - -### 题解 1: 广度优先搜索 -* 时间: `O(10^4)`. -* 空间: `O(N)`. - -### 题解 2: A* (A-Star) 算法 -* 时间: `O(5 * 4 * 4 * 2 + N)`. -* 空间: `O(N)`. - -## Python -### 题解 1: 广度优先搜索 -```python -class Solution: - def openLock(self, deadends: List[str], target_digits: str) -> int: - if '0000' == target_digits: - return 0 - - self.deadends = set(deadends) - if '0000' in deadends: - return -1 - - self.queue = deque(['0000']) - self.deadends.add('0000') - self.target_digits = target_digits - result = 0 - - while self.queue: - result += 1 - queue_size = len(self.queue) - - for _ in range(queue_size): - digits = self.queue.popleft() - - if self.turn_one_slot(digits): - return result - - return -1 - - def turn_one_slot(self, digits): - for i in range(len(digits)): - for digit in closest_digits(int(digits[i])): - new_digits = f'{digits[:i]}{digit}{digits[i + 1:]}' - - if new_digits == self.target_digits: - return True - - if new_digits in self.deadends: - continue - - self.queue.append(new_digits) - self.deadends.add(new_digits) - - -def closest_digits(digit): - if digit == 0: - return (9, 1) - - if digit == 9: - return (8, 0) - - return (digit - 1, digit + 1) -``` - -### 题解 2: A* (A-Star) 算法 -```python -class Solution: - def openLock(self, deadends: List[str], target_digits: str) -> int: - if '0000' == target_digits: - return 0 - - deadends = set(deadends) - if '0000' in deadends: - return -1 - - self.target_digits = target_digits - - priority_queue = [(self.distance('0000'), '0000', 0)] - - while priority_queue: - _, digits, turns = heapq.heappop(priority_queue) - - for i in range(4): - for digit in closest_digits(int(digits[i])): - new_digits = f'{digits[:i]}{digit}{digits[i + 1:]}' - - if new_digits == target_digits: - return turns + 1 - - if new_digits in deadends: - continue - - heapq.heappush( - priority_queue, - (self.distance(new_digits), new_digits, turns + 1) - ) - deadends.add(new_digits) - - return -1 - - def distance(self, digits): - result = 0 - - # 0 1 2 3 4 5 6 7 8 9 - # 0 1 2 3 4 5 6 7 8 9 - # 0 1 2 3 4 5 6 7 8 9 - # 0 1 2 3 4 5 6 7 8 9 - for i in range(4): - # 'Euclidean Distance' is widely used in 'A* Algorithm'. - result += abs(int(self.target_digits[i]) - int(digits[i])) ** 2 - - return result ** 0.5 - - -def closest_digits(digit): - if digit == 0: - return (9, 1) - - if digit == 9: - return (8, 0) - - return (digit - 1, digit + 1) -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/787-cheapest-flights-within-k-stops.md b/zh/1-1000/787-cheapest-flights-within-k-stops.md deleted file mode 100644 index 799cbc8..0000000 --- a/zh/1-1000/787-cheapest-flights-within-k-stops.md +++ /dev/null @@ -1,125 +0,0 @@ -# 787. K 站中转内最便宜的航班 - 力扣题解最佳实践 -力扣链接:[787. K 站中转内最便宜的航班](https://leetcode.cn/problems/cheapest-flights-within-k-stops),难度: **中等**。 - -## 力扣“787. K 站中转内最便宜的航班”问题描述 -有 `n` 个城市通过一些航班连接。给你一个数组 `flights` ,其中 `flights[i] = [fromi, toi, pricei]` ,表示该航班都从城市 `fromi` 开始,以价格 `pricei` 抵达 `toi`。 - -现在给定所有的城市和航班,以及出发城市 `src` 和目的地 `dst`,你的任务是找到出一条最多经过 `k` 站中转的路线,使得从 `src` 到 `dst` 的 **价格最便宜** ,并返回该价格。 如果不存在这样的路线,则输出 `-1`。 - -### [示例 1] -![](../../images/examples/787_1.png) - -**输入**: `n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1` - -**输出**: `700` - -**解释**: -``` -城市航班图如上 -从城市 0 到城市 3 经过最多 1 站的最佳路径用红色标记,费用为 100 + 600 = 700。 -请注意,通过城市 [0, 1, 2, 3] 的路径更便宜,但无效,因为它经过了 2 站。 -``` - -### [示例 2] -**输入**: `n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1` - -**输出**: `200` - -**解释**: -``` -城市航班图如上 -从城市 0 到城市 2 经过最多 1 站的最佳路径标记为红色,费用为 100 + 100 = 200。 -``` - -### [示例 3] -**输入**: `n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 0` - -**输出**: `500` - -**解释**: -``` -城市航班图如上 -从城市 0 到城市 2 不经过站点的最佳路径标记为红色,费用为 500。 -``` - -### [约束] -- `1 <= n <= 100` -- `0 <= flights.length <= (n * (n - 1) / 2)` -- `flights[i].length == 3` -- `0 <= from_i, to_i < n` -- `from_i != to_i` -- `1 <= price_i <= 10000` -- 航班没有重复,且不存在自环 -- `0 <= src, dst, k < n` -- `src != dst` - -## 思路 -本题可用 **Bellman-Ford算法** 解决。 - -**Bellman-Ford算法**的详细说明,请参考 [743. 网络延迟时间](./743-network-delay-time.md)。 - -## 复杂度 -**V**: 顶点数量,**E**: 边的数量。 - -* 时间: `O(K * E)`. -* 空间: `O(V)`. - -## Python -```python -class Solution: - def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int: - min_costs = [float('inf')] * n - min_costs[src] = 0 - - for _ in range(k + 1): - min_costs_clone = min_costs.copy() - - for from_city, to_city, price in flights: - if min_costs_clone[from_city] == float('inf'): - continue - - cost = min_costs_clone[from_city] + price - - if cost < min_costs[to_city]: - min_costs[to_city] = cost - - if min_costs[dst] == float('inf'): - return -1 - - return min_costs[dst] -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/797-all-paths-from-source-to-target.md b/zh/1-1000/797-all-paths-from-source-to-target.md deleted file mode 100644 index bd8ee95..0000000 --- a/zh/1-1000/797-all-paths-from-source-to-target.md +++ /dev/null @@ -1,866 +0,0 @@ -# 797. 所有可能的路径 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[797. 所有可能的路径 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/797-all-paths-from-source-to-target),体验更佳! - -力扣链接:[797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target), 难度等级:**中等**。 - -## LeetCode “797. 所有可能的路径”问题描述 - -给你一个有 `n` 个节点的 **有向无环图(DAG)**,请你找出所有从节点 `0` 到节点 `n-1` 的路径并输出(**不要求按特定顺序**) - -`graph[i]` 是一个从节点 `i` 可以访问的所有节点的列表(即从节点 `i` 到节点 `graph[i][j]` 存在一条有向边)。 - -### [示例 1] - -![](../../images/examples/797_1.jpg) - -**输入**: `graph = [[1,2],[3],[3],[]]` - -**输出**: `[[0,1,3],[0,2,3]]` - -**解释**: `有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3` - -### [示例 2] - -![](../../images/examples/797_2.jpg) - -**输入**: `graph = [[4,3,1],[3,2,4],[3],[4],[]]` - -**输出**: `[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]` - -### [约束] - -- `n == graph.length` -- `2 <= n <= 15` -- `0 <= graph[i][j] < n` -- `graph[i][j] != i`(即不存在自环) -- `graph[i]` 中的所有元素 **互不相同** -- 保证输入为 **有向无环图(DAG)** - -## 思路 1 - - - -## “深度优先搜索”的模式 - -深度优先搜索(DFS)是一种经典的图遍历算法,其核心特点是**“尽可能深”**地探索图的分支。DFS 从起始顶点出发,沿着一条路径不断深入,直到到达没有未访问邻接点的顶点,然后回溯到最近的分叉点继续探索。这一过程通过**递归**或**显式栈(迭代法)**实现,形成“后进先出”的搜索顺序,因此 DFS 在非加权图中能快速找到离起点较远的深层节点。 - -**与 BFS 的对比**: - -1. **搜索顺序**:DFS 优先探索深度方向,而广度优先搜索(BFS)按层逐层扩展,形成“先进先出”的队列结构。 -2. **适用场景**:DFS 更适合强连通分量或回溯类问题(如迷宫所有路径),而 BFS 擅长最短路径(未加权图)或邻近节点探索(如社交网络好友推荐)。 - -**DFS 的独特性**: - -- **不完全性**:若图无限深或存在环路(未标记已访问),DFS 可能无法终止,而 BFS 总能找到最短路径(未加权图)。 -- **“一支笔走到底”** 的搜索风格,使其在回溯剪枝或记录路径时更具灵活性,但也可能错过近邻最优解。 - - -总之,DFS 以深度优先的策略揭示图的纵向结构,其回溯特性与栈的天然结合,使其在路径记录和状态空间探索中表现突出,但需注意处理环路和最优解缺失的局限性。 - -## 步骤 - -1. 初始化一个空列表 `paths`,用于存储所有找到的有效路径。 -2. 初始化一个堆栈来管理 DFS 遍历。堆栈中的每个元素将存储一个 pair(或元组),其中包含当前 `node` 和到达该节点所采用的 `path`。 -3. 将起始状态加入到堆栈:初始节点 `0` 和一个空的路径列表(例如 `(0, [])`)。 -4. 当堆栈不为空时: - - 从堆栈中弹出顶部元素,检索当前 `node` 及其关联的 `path`。 - - 通过将当前 `node` 附加到从堆栈中弹出的 `path` 来创建一个 `currentPath` 数组,它表示通往当前节点并包含当前节点的路径。 - - 检查当前 `node` 是否为目标节点(`n - 1`,其中 `n` 是节点总数)。 - - 如果它是目标节点,则将 `currentPath` 添加到 `paths` 数组中,因为已经找到了从源节点到目标节点的完整路径。 - - 如果不是目标节点,则遍历当前 `node` 可访问的所有 `neighbor` 节点(即遍历 `graph[node]`)。 - - 对于每个 `neighbor`,将一个新的 pair(`neighbor` 节点和 `currentPath`)加入到堆栈中。这为遍历探索从邻居节点延伸的路径做好准备。 -5. 循环结束后(堆栈为空),返回 `paths` 数组,其中包含从节点 `0` 到节点 `n - 1` 的所有已发现路径。 - -## 复杂度 - -- 时间复杂度: `Too complex`. -- 空间复杂度: `Too complex`. - -## Python - -```python -class Solution: - def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: - paths = [] - stack = [(0, [])] - - while stack: - node, path = stack.pop() - - if node == len(graph) - 1: - paths.append(path + [node]) - continue - - for target_node in graph[node]: - stack.append((target_node, path + [node])) - - return paths -``` - -## Java - -```java -class Solution { - public List> allPathsSourceTarget(int[][] graph) { - List> paths = new ArrayList<>(); - // Each element in the stack is a pair: (current_node, current_path) - Stack>> stack = new Stack<>(); - List initialPath = new ArrayList<>(); - stack.push(new Pair<>(0, initialPath)); - - int targetNode = graph.length - 1; - - while (!stack.isEmpty()) { - var current = stack.pop(); - int node = current.getKey(); - var path = current.getValue(); - - var nextPath = new ArrayList<>(path); - nextPath.add(node); - - if (node == targetNode) { - paths.add(nextPath); - continue; - } - - for (int neighbor : graph[node]) { - stack.push(new Pair<>(neighbor, nextPath)); - } - } - - return paths; - } -} - -``` - -## C++ - -```cpp -class Solution { -public: - vector> allPathsSourceTarget(vector>& graph) { - vector> paths; - // Stack stores pairs of (current_node, current_path) - stack>> s; - s.push({0, {}}); // Start at node 0 with an empty path initially - - int targetNode = graph.size() - 1; - - while (!s.empty()) { - auto node_path = s.top(); - s.pop(); - int node = node_path.first; - vector path = node_path.second; - - // Add the current node to the path - path.push_back(node); - - if (node == targetNode) { - paths.push_back(path); // Found a path to the target - continue; - } - - // Explore neighbors - for (int neighbor : graph[node]) { - s.push({neighbor, path}); - } - } - - return paths; - } -}; -``` - -## JavaScript - -```javascript -/** - * @param {number[][]} graph - * @return {number[][]} - */ -var allPathsSourceTarget = function(graph) { - const paths = []; - // Stack stores arrays: [current_node, current_path] - const stack = [[0, []]]; // Start at node 0 with an empty path - const targetNode = graph.length - 1; - - while (stack.length > 0) { - const [node, path] = stack.pop(); - - // Create the new path by appending the current node - const currentPath = [...path, node]; - - if (node === targetNode) { - paths.push(currentPath); // Found a path - continue; - } - - // Explore neighbors - for (const neighbor of graph[node]) { - stack.push([neighbor, currentPath]); // Push neighbor and the path so far - } - } - - return paths; -}; - -``` - -## C# - -```csharp -public class Solution { - public IList> AllPathsSourceTarget(int[][] graph) - { - var paths = new List>(); - // Stack stores tuples: (current_node, current_path) - var stack = new Stack<(int node, List path)>(); - stack.Push((0, new List())); // Start at node 0 - - int targetNode = graph.Length - 1; - - while (stack.Count > 0) - { - var (node, path) = stack.Pop(); - - var currentPath = new List(path); - currentPath.Add(node); - - if (node == targetNode) - { - paths.Add(currentPath); // Found a path - continue; - } - - // Explore neighbors - foreach (int neighbor in graph[node]) - { - stack.Push((neighbor, currentPath)); // Push neighbor and the path so far - } - } - - return paths; - } -} -``` - -## Go - -```go -type StackItem struct { - Node int - Path []int -} - -func allPathsSourceTarget(graph [][]int) [][]int { - var paths [][]int - stack := []StackItem{{Node: 0, Path: []int{}}} // Start at node 0 - - targetNode := len(graph) - 1 - - for len(stack) > 0 { - currentItem := stack[len(stack) - 1] // Pop from stack - stack = stack[:len(stack) - 1] - - node := currentItem.Node - path := currentItem.Path - - newPath := append([]int(nil), path...) - newPath = append(newPath, node) - - if node == targetNode { - paths = append(paths, newPath) // Found a path - continue - } - - for _, neighbor := range graph[node] { - stack = append(stack, StackItem{Node: neighbor, Path: newPath}) - } - } - - return paths -} -``` - -## Ruby - -```ruby -# @param {Integer[][]} graph -# @return {Integer[][]} -def all_paths_source_target(graph) - paths = [] - # Stack stores arrays: [current_node, current_path] - stack = [[0, []]] # Start at node 0 with an empty path - target_node = graph.length - 1 - - while !stack.empty? - node, path = stack.pop - - # Create the new path by appending the current node - current_path = path + [node] - - if node == target_node - paths << current_path # Found a path - next - end - - # Explore neighbors - graph[node].each do |neighbor| - stack.push([neighbor, current_path]) - end - end - - paths -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - - - -## “深度优先搜索”的模式 - -深度优先搜索(DFS)是一种经典的图遍历算法,其核心特点是**“尽可能深”**地探索图的分支。DFS 从起始顶点出发,沿着一条路径不断深入,直到到达没有未访问邻接点的顶点,然后回溯到最近的分叉点继续探索。这一过程通过**递归**或**显式栈(迭代法)**实现,形成“后进先出”的搜索顺序,因此 DFS 在非加权图中能快速找到离起点较远的深层节点。 - -**与 BFS 的对比**: - -1. **搜索顺序**:DFS 优先探索深度方向,而广度优先搜索(BFS)按层逐层扩展,形成“先进先出”的队列结构。 -2. **适用场景**:DFS 更适合强连通分量或回溯类问题(如迷宫所有路径),而 BFS 擅长最短路径(未加权图)或邻近节点探索(如社交网络好友推荐)。 - -**DFS 的独特性**: - -- **不完全性**:若图无限深或存在环路(未标记已访问),DFS 可能无法终止,而 BFS 总能找到最短路径(未加权图)。 -- **“一支笔走到底”** 的搜索风格,使其在回溯剪枝或记录路径时更具灵活性,但也可能错过近邻最优解。 - - -总之,DFS 以深度优先的策略揭示图的纵向结构,其回溯特性与栈的天然结合,使其在路径记录和状态空间探索中表现突出,但需注意处理环路和最优解缺失的局限性。 - -## “递归”的模式 - -递归(Recursion)是计算机科学和数学中的一个重要概念,指的是 一个函数在其定义中 **直接或间接调用自身** 的方法。 - -### 递归的核心思想 - -- **自我调用**:函数在执行过程中调用自身。 -- **基线情况**:相当于终止条件。到达基线情况后,就可以返回结果了,不需要再递归调用,防止无限循环。 -- **递归步骤**:问题逐步向“基线情况”靠近的步骤。 - -## 步骤 - -1. 初始化一个空数组 `paths`,用于存储从源节点到目标节点找到的所有有效路径。 -2. 定义一个递归深度优先搜索 (DFS) 函数,例如 `dfs`,它将当前 `node` 和 `path`(即迄今为止访问过的节点列表,用于到达当前节点)作为输入。 -3. 在 `dfs` 函数内部: - - 通过将当前 `node` 附加到 `path` 来创建一个新的路径列表。我们将其称为 `newPath`。 - - 检查当前 `node` 是否为目标节点(`n - 1`,其中 `n` 是节点总数)。 - - 如果是目标节点,则表示我们找到了一条完整的路径。将 `newPath` 添加到主 `paths` 数组中,并从此递归调用返回。 - - 如果当前 `node` 不是目标节点,则遍历所有可从当前 `node` 访问的 `neighbor` 节点(即遍历 `graph[node]`)。 - - 对于每个 `neighbor`,以 `neighbor` 作为新的当前节点,以 `newPath` 作为到达该节点的路径,对 `dfs` 进行递归调用 (`dfs(neighbor, newPath)`)。 -4. 通过使用源节点 `0` 和空的初始路径 (`dfs(0, [])`) 调用 `dfs` 函数来启动该过程。 -5. 初始 `dfs` 调用完成后,返回包含所有已发现路径的 `paths` 数组。 - -## 复杂度 - -- 时间复杂度: `Too complex`. -- 空间复杂度: `Too complex`. - -## Python - -```python -class Solution: - def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: - self.paths = [] - self.graph = graph - self.target = len(graph) - 1 - - self.dfs(0, []) # Start DFS from node 0 with an empty initial path - - return self.paths - - def dfs(self, node, path): - current_path = path + [node] - - if node == self.target: # Base case - self.paths.append(current_path) - return - - for neighbor in self.graph[node]: # Recursive step: Explore neighbors - self.dfs(neighbor, current_path) -``` - -## Java - -```java -class Solution { - private List> paths; - private int[][] graph; - private int targetNode; - - public List> allPathsSourceTarget(int[][] graph) { - this.paths = new ArrayList<>(); - this.graph = graph; - this.targetNode = graph.length - 1; - - List initialPath = new ArrayList<>(); - dfs(0, initialPath); // Start DFS from node 0 with an empty initial path - - return paths; - } - - private void dfs(int node, List currentPath) { - List newPath = new ArrayList<>(currentPath); - newPath.add(node); - - if (node == targetNode) { // Base case - paths.add(newPath); - return; - } - - for (int neighbor : graph[node]) { // Recursive step: Explore neighbors - dfs(neighbor, newPath); - } - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> allPathsSourceTarget(vector>& graph) { - _graph = graph; - - vector initial_path; // Empty initial path - dfs(0, initial_path); // Start DFS from node 0 - - return _paths; - } - -private: - vector> _paths; - vector> _graph; - - void dfs(int node, vector current_path) { - current_path.push_back(node); - - if (node == _graph.size() - 1) { // Base case - _paths.push_back(current_path); - return; - } - - for (int neighbor : _graph[node]) { // Recursive step: Explore neighbors - dfs(neighbor, current_path); - } - } -}; -``` - -## JavaScript - -```javascript -let paths -let graph - -var allPathsSourceTarget = function (graph_) { - paths = [] - graph = graph_ - - dfs(0, []) - - return paths -} - -function dfs(node, currentPath) { - const newPath = [...currentPath, node] - - if (node === graph.length - 1) { // Base case - paths.push(newPath) - return - } - - for (const neighbor of graph[node]) { // Recursive step: Explore neighbors - dfs(neighbor, newPath) - } -} - -``` - -## C# - -```csharp -public class Solution -{ - private IList> paths; - private int[][] graph; - private int targetNode; - - public IList> AllPathsSourceTarget(int[][] graph) - { - this.paths = new List>(); - this.graph = graph; - this.targetNode = graph.Length - 1; - - Dfs(0, new List()); - - return paths; - } - - private void Dfs(int node, List currentPath) - { - var newPath = new List(currentPath); - newPath.Add(node); - - if (node == targetNode) // Base case - { - paths.Add(newPath); - return; - } - - foreach (int neighbor in graph[node]) // Recursive step: Explore neighbors - { - Dfs(neighbor, newPath); - } - } -} -``` - -## Go - -```go -var ( - paths [][]int - graph [][]int - targetNode int -) - -func allPathsSourceTarget(graph_ [][]int) [][]int { - paths = [][]int{} - graph = graph_ - targetNode = len(graph) - 1 - - dfs(0, []int{}) - - return paths -} - -func dfs(node int, currentPath []int) { - newPath := append([]int(nil), currentPath...) - newPath = append(newPath, node) - - if node == targetNode { // Base case - paths = append(paths, newPath) - return - } - - for _, neighbor := range graph[node] { // Recursive step: Explore neighbors - dfs(neighbor, newPath) - } -} -``` - -## Ruby - -```ruby -def all_paths_source_target(graph) - @paths = [] - @graph = graph - - dfs(0, []) - - @paths -end - -def dfs(node, current_path) - new_path = current_path + [node] - - if node == @graph.size - 1 # Base case - @paths << new_path - return - end - - @graph[node].each do |neighbor| # Recursive step: Explore neighbors - dfs(neighbor, new_path) - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 3 - - - -## “深度优先搜索”的模式 - -深度优先搜索(DFS)是一种经典的图遍历算法,其核心特点是**“尽可能深”**地探索图的分支。DFS 从起始顶点出发,沿着一条路径不断深入,直到到达没有未访问邻接点的顶点,然后回溯到最近的分叉点继续探索。这一过程通过**递归**或**显式栈(迭代法)**实现,形成“后进先出”的搜索顺序,因此 DFS 在非加权图中能快速找到离起点较远的深层节点。 - -**与 BFS 的对比**: - -1. **搜索顺序**:DFS 优先探索深度方向,而广度优先搜索(BFS)按层逐层扩展,形成“先进先出”的队列结构。 -2. **适用场景**:DFS 更适合强连通分量或回溯类问题(如迷宫所有路径),而 BFS 擅长最短路径(未加权图)或邻近节点探索(如社交网络好友推荐)。 - -**DFS 的独特性**: - -- **不完全性**:若图无限深或存在环路(未标记已访问),DFS 可能无法终止,而 BFS 总能找到最短路径(未加权图)。 -- **“一支笔走到底”** 的搜索风格,使其在回溯剪枝或记录路径时更具灵活性,但也可能错过近邻最优解。 - - -总之,DFS 以深度优先的策略揭示图的纵向结构,其回溯特性与栈的天然结合,使其在路径记录和状态空间探索中表现突出,但需注意处理环路和最优解缺失的局限性。 - -## 步骤 - -1. 初始化一个空列表 `paths`,用于存储从源节点到目标节点找到的所有有效路径。 -2. 创建一个可变列表 `path`,用于跟踪当前正在探索的路径,初始仅包含源节点 `0`。 -3. 实现一个使用回溯法探索路径的递归 DFS 函数: - - 基线情况:如果当前节点是目标节点 (`n-1`),则复制当前路径并将其添加到 `paths` 列表中。 - - 递归步骤:对于当前节点的每个邻居: - - 将邻居添加到当前路径。 - - 使用此邻居递归调用 DFS 函数。 - - 递归调用返回后,从路径中删除邻居(回溯)。 -4. 从源节点 `0` 开始 DFS。 -5. DFS 完成后,返回收集到的 `paths`。 - -## 复杂度 - -- 时间复杂度: `Too complex`. -- 空间复杂度: `Too complex`. - -## Python - -```python -class Solution: - def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: - self.paths = [] - self.graph = graph - self.path = [0] # Important - - self.dfs(0) - - return self.paths - - def dfs(self, node): - if node == len(self.graph) - 1: - self.paths.append(self.path.copy()) # Important - return - - for neighbor in self.graph[node]: - self.path.append(neighbor) # Important - self.dfs(neighbor) - self.path.pop() # Important - -``` - -## Java - -```java -class Solution { - private List> paths = new ArrayList<>(); - private List path = new ArrayList<>(List.of(0)); // Important - start with node 0 - private int[][] graph; - - public List> allPathsSourceTarget(int[][] graph) { - this.graph = graph; - - dfs(0); - - return paths; - } - - private void dfs(int node) { - if (node == graph.length - 1) { // Base case - paths.add(new ArrayList<>(path)); // Important - make a copy - return; - } - - for (int neighbor : graph[node]) { // Recursive step - path.add(neighbor); // Important - dfs(neighbor); - path.remove(path.size() - 1); // Important - backtrack - } - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector> allPathsSourceTarget(vector>& graph) { - _graph = graph; - _path = {0}; // Important - start with node 0 - - dfs(0); - - return _paths; - } - -private: - vector> _paths; - vector> _graph; - vector _path; - - void dfs(int node) { - if (node == _graph.size() - 1) { // Base case - _paths.push_back(_path); // Important - copy is made automatically - return; - } - - for (int neighbor : _graph[node]) { // Recursive step - _path.push_back(neighbor); // Important - dfs(neighbor); - _path.pop_back(); // Important - backtrack - } - } -}; - -``` - -## JavaScript - -```javascript -/** - * @param {number[][]} graph - * @return {number[][]} - */ -var allPathsSourceTarget = function(graph) { - const paths = []; - const path = [0]; // Important - start with node 0 - - function dfs(node) { - if (node === graph.length - 1) { // Base case - paths.push([...path]); // Important - make a copy - return; - } - - for (const neighbor of graph[node]) { // Recursive step - path.push(neighbor); // Important - dfs(neighbor); - path.pop(); // Important - backtrack - } - } - - dfs(0); - - return paths; -}; -``` - -## C# - -```csharp -public class Solution -{ - private IList> paths = new List>(); - private List path = new List { 0 }; // Important - start with node 0 - private int[][] graph; - - public IList> AllPathsSourceTarget(int[][] graph) - { - this.graph = graph; - - Dfs(0); - - return paths; - } - - private void Dfs(int node) - { - if (node == graph.Length - 1) - { // Base case - paths.Add(new List(path)); // Important - make a copy - return; - } - - foreach (int neighbor in graph[node]) - { // Recursive step - path.Add(neighbor); // Important - Dfs(neighbor); - path.RemoveAt(path.Count - 1); // Important - backtrack - } - } -} -``` - -## Go - -```go -func allPathsSourceTarget(graph [][]int) [][]int { - paths := [][]int{} - path := []int{0} // Important - start with node 0 - - var dfs func(int) - dfs = func(node int) { - if node == len(graph) - 1 { // Base case - // Important - make a deep copy of the path - paths = append(paths, append([]int(nil), path...)) - return - } - - for _, neighbor := range graph[node] { // Recursive step - path = append(path, neighbor) // Important - dfs(neighbor) - path = path[:len(path) - 1] // Important - backtrack - } - } - - dfs(0) - - return paths -} -``` - -## Ruby - -```ruby -# @param {Integer[][]} graph -# @return {Integer[][]} -def all_paths_source_target(graph) - @paths = [] - @graph = graph - @path = [0] # Important - start with node 0 - - dfs(0) - - @paths -end - -def dfs(node) - if node == @graph.length - 1 # Base case - @paths << @path.clone # Important - make a copy - return - end - - @graph[node].each do |neighbor| # Recursive step - @path << neighbor # Important - dfs(neighbor) - @path.pop # Important - backtrack - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[797. 所有可能的路径 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/797-all-paths-from-source-to-target). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/827-making-a-large-island.md b/zh/1-1000/827-making-a-large-island.md deleted file mode 100644 index a778880..0000000 --- a/zh/1-1000/827-making-a-large-island.md +++ /dev/null @@ -1,201 +0,0 @@ -# LeetCode 827. Making A Large Island's Solution -LeetCode link: [827. Making A Large Island](https://leetcode.com/problems/making-a-large-island/) - -## LeetCode problem description -You are given an `n x n` binary matrix `grid`. You are allowed to change at most one `0` to be `1`. - -Return the size of the largest island in `grid` after applying this operation. - -An island is a 4-directionally connected group of `1`s. - -### Example 1 -``` -Input: grid = [ - [1,0], - [0,1] -] -Output: 3 -Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3. -``` - -### Example 2 -``` -Input: grid = [ - [1,1], - [1,0] -] -Output: 4 -Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4. -``` -### Example 3 -``` -Input: grid = [ - [1,1], - [1,1] -] -Output: 4 -Explanation: Can't change any 0 to 1, only one island with area = 4. -``` - -### Constraints -- `n == grid.length` -- `n == grid[i].length` -- `1 <= n <= 500` -- `grid[i][j]` is either `0` or `1`. - -## Intuition -This problem is hard. Before solving this problem, you can do the following two problems first: - -- [200. Number of Islands](200-number-of-islands.md) -- [695. Max Area of Island](695-max-area-of-island.md) - -The island problem can be abstracted into a **graph theory** problem. This is an **undirected graph**: - -![](../../images/graph_undirected_1.svg) - -And this graph may have multiple **connected components** (islands): - -![](../../images/graph_undirected_2.png) - -## Approach -1. Change one vertex from `0` to `1` to make the largest island means combining the adjacent islands of a `0` vertex. -1. We can mark an island's lands with one same id (`island_id`), and mark another island's lands with another `island_id`. To mark a land, just change its value to the `island_id`. -1. Use a `map` (or an `array`) to map each `island_id` to its `area`. -1. How to calculate the area of an island? Using `Depth-First Search` or `Breadth-First Search`. See [695. Max Area of Island](695-max-area-of-island.md). -1. Iterate through each `0` (water), then sum the `areas` of neighboring islands. -1. Record the max area and return it. - -## Complexity -* Time: `O(n * n)`. -* Space: `O(n * n)`. - -## Python -```python -from collections import defaultdict - -class Solution: - def __init__(self): - self.island_id = 2 - self.island_id_to_area = defaultdict(int) - - def largestIsland(self, grid: List[List[int]]) -> int: - self.grid = grid - max_area = 0 - - for i in range(len(grid)): - for j in range(len(grid[0])): - if self.grid[i][j] == 1: - self.depth_first_search(i, j) - self.island_id += 1 - - has_water = False - - for i in range(len(grid)): - for j in range(len(grid[0])): - if self.grid[i][j] == 0: - has_water = True - max_area = max(max_area, self.combined_islands_area(i, j)) - - if not has_water: - return len(grid) * len(grid[0]) - - return max_area - - def depth_first_search(self, i, j): - if i < 0 or j < 0 or i >= len(self.grid) or j >= len(self.grid[0]): - return - - if self.grid[i][j] != 1: - return - - self.grid[i][j] = self.island_id - self.island_id_to_area[self.island_id] += 1 - - for a, b in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0) - ]: - m = i + a - n = j + b - self.depth_first_search(m, n) - - def combined_islands_area(self, i, j): - island_ids = set() - - for a, b in [ - (-1, 0), - (0, -1), (0, 1), - (1, 0) - ]: - m = i + a - n = j + b - - if m < 0 or n < 0 or m >= len(self.grid) or n >= len(self.grid[0]): - continue - - if self.grid[m][n] != 0: - island_ids.add(self.grid[m][n]) - - area = 1 - - for island_id in island_ids: - area += self.island_id_to_area[island_id] - - return area -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/833-find-and-replace-in-string.md b/zh/1-1000/833-find-and-replace-in-string.md deleted file mode 100644 index f1a3a65..0000000 --- a/zh/1-1000/833-find-and-replace-in-string.md +++ /dev/null @@ -1,114 +0,0 @@ -# 833. 字符串中的查找与替换 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[833. 字符串中的查找与替换 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/833-find-and-replace-in-string),体验更佳! - -力扣链接:[833. 字符串中的查找与替换](https://leetcode.cn/problems/find-and-replace-in-string), 难度等级:**中等**。 - -## LeetCode “833. 字符串中的查找与替换”问题描述 - -你会得到一个字符串 `s` (索引从 0 开始),你必须对它执行 `k` 个替换操作。替换操作以三个长度均为 `k` 的并行数组给出:`indices`, `sources`, `targets`。 - -要完成第 `i` 个替换操作: - -1. 检查 **子字符串** `sources[i]` 是否出现在 **原字符串** `s` 的索引 `indices[i]` 处。 -2. 如果没有出现, **什么也不做** 。 -3. 如果出现,则用 `targets[i]` **替换** 该子字符串。 - -例如,如果 `s = "abcd"` , `indices[i] = 0` , `sources[i] = "ab"`, `targets[i] = "eee"` ,那么替换的结果将是 `"eeecd"` 。 - -所有替换操作必须 **同时** 发生,这意味着替换操作不应该影响彼此的索引。测试用例保证元素间**不会重叠** 。 - -- 例如,一个 `s = "abc"` , `indices = [0,1]` ,`sources = ["ab","bc"]` 的测试用例将不会生成,因为 `"ab"` 和 `"bc"` 替换重叠。 - -在对 `s` 执行所有替换操作后返回 **结果字符串** 。 - -**子字符串** 是字符串中连续的字符序列。 - -### [示例 1] - -![](../../images/examples/833_1.png) - -**输入**: `s = "abcd", indices = [0,2], sources = ["a","cd"], targets = ["eee","ffff"]` - -**输出**: `"eeebffff"` - -**解释**: - -

"a" 从 s 中的索引 0 开始,所以它被替换为 "eee"。
-"cd" 从 s 中的索引 2 开始,所以它被替换为 "ffff"。

- - -### [示例 2] - -![](../../images/examples/833_2.png) - -**输入**: `s = "abcd", indices = [0, 2], sources = ["ab","ec"], targets = ["eee","ffff"]` - -**输出**: `"eeecd"` - -**解释**: - -

"ab" 从 s 中的索引 0 开始,所以它被替换为 "eee"。
-"ec" 没有从原始的 S 中的索引 2 开始,所以它没有被替换。

- - -### [约束] - -- `1 <= s.length <= 1000` -- `k == indices.length == sources.length == targets.length` -- `1 <= k <= 100` -- `0 <= indexes[i] < s.length` -- `1 <= sources[i].length, targets[i].length <= 50` -- `s` consists of only lowercase English letters. -- `sources[i]` and `targets[i]` consist of only lowercase English letters. - -## 思路 - -这道题目看起来简单,做起来还挺花时间的。 - -- 问题一:对于所求的目标字符串`result`,可以基于原字符串的克隆,也可以从空字符串构建,哪个更好呢? -
点击查看答案

基于原字符串的克隆比较好。因为你省去了不少子字符串的赋值操作。

- -- 问题二:在用`targets[i]`替换`result`的子字符串后,`result`的长度可能会变化,这导致后面的替换变得困难。如何解决? -
点击查看答案

用技术手段让`result`的长度,在经历字符串替换后,始终保持不变。

- -## 复杂度 - -> N = s.length - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def findReplaceString(self, s: str, indices: List[int], sources: List[str], targets: List[str]) -> str: - result = list(s) - - for i in range(len(indices)): - index = indices[i] - - if s[index:index + len(sources[i])] == sources[i]: - for j in range(index, index + len(sources[i])): - if j == index: - result[j] = targets[i] - else: - result[j] = '' - - return ''.join(result) -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[833. 字符串中的查找与替换 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/833-find-and-replace-in-string). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1-1000/84-largest-rectangle-in-histogram.md b/zh/1-1000/84-largest-rectangle-in-histogram.md deleted file mode 100644 index 40f1e98..0000000 --- a/zh/1-1000/84-largest-rectangle-in-histogram.md +++ /dev/null @@ -1,267 +0,0 @@ -# 84. Largest Rectangle in Histogram (Monotonic Stack Solution) -LeetCode link: [84. Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) - -## LeetCode problem description -Given an array of integers `heights` representing the histogram's bar height where the width of each bar is `1`, return the area of the largest rectangle in the histogram. - -### Example 1 -![](../../images/examples/84_1.jpg) -``` -Input: heights = [2,1,5,6,2,3] -Output: 10 - -Explanation: The above is a histogram where width of each bar is 1. -The largest rectangle is shown in the red area, which has an area = 10 units. -``` - -### Example 2 -![](../../images/examples/84_2.jpg) -``` -Input: heights = [2,4] -Output: 4 -``` - -### Constraints -- `1 <= heights.length <= 100000` -- `0 <= heights[i] <= 10000` - -## Thoughts -This problem can be solved using **Monotonic Stack**. - -* The `heights` in the stack from bottom to top are in ascending order. -* While `current_height < stack_top_height`, pop `stack_top_height`. -* Follow **Monotonic Stack**'s common rule: **only calculating when `pop()` is happening**. This common rule can be applied to calculating result for **most** of the `Monotonic Stack` problems. -* Disappeared heights (popped by `current_height` or popped by `stack_top_height`) are all taller than `stack_top_height`. This logic will be used to calculate the `width`. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -```python -class Solution: - def largestRectangleArea(self, heights: List[int]) -> int: - heights = [0] + heights + [0] - max_area = 0 - index_stack = [] - - for i, height in enumerate(heights): - while index_stack and height < heights[index_stack[-1]]: - popped_index = index_stack.pop() - - popped_height = heights[popped_index] - - left_index = index_stack[-1] # popped_height's remaining left heights are all shorter than 'popped_height', because when 'popped_height' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - right_index = i # popped_height's right heights (which are all taller than 'popped_height') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - width = right_index - left_index - 1 # So in the range of 'width', they are all no shorter than `popped_height`, although they have been popped out of the stack (disappeared). - - area = popped_height * width - if area > max_area: - max_area = area - - index_stack.append(i) - - return max_area -``` - -## Java -```java -class Solution { - public int largestRectangleArea(int[] heightArray) { - var heights = new int[heightArray.length + 2]; - System.arraycopy(heightArray, 0, heights, 1, heightArray.length); - - var maxArea = 0; - var indexStack = new Stack(); - - for (var i = 0; i < heights.length; i++) { - while (!indexStack.empty() && heights[i] < heights[indexStack.peek()]) { - var poppedIndex = indexStack.pop(); - - var poppedHeight = heights[poppedIndex]; - var leftIndex = indexStack.peek(); // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - var rightIndex = i; // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - var width = rightIndex - leftIndex - 1; // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - var area = poppedHeight * width; - if (area > maxArea) { - maxArea = area; - } - } - - indexStack.push(i); - } - - return maxArea; - } -} -``` - -## C++ -```cpp -class Solution { -public: - int largestRectangleArea(vector heights) { - heights.insert(heights.begin(), 0); - heights.push_back(0); - auto max_area = 0; - stack index_stack; - - for (auto i = 0; i < heights.size(); i++) { - while (!index_stack.empty() && heights[i] < heights[index_stack.top()]) { - auto popped_height = heights[index_stack.top()]; - - index_stack.pop(); - - auto left_index = index_stack.top(); // popped_height's remaining left heights are all shorter than it, because when 'popped_height' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - auto right_index = i; // popped_height's right heights (which are all taller than 'popped_height') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - auto width = right_index - left_index - 1; // So in the range of 'width', they are all no shorter than `popped_height`, although they have been popped out of the stack (disappeared). - - auto area = popped_height * width; - if (area > max_area) { - max_area = area; - } - } - - index_stack.push(i); - } - - return max_area; - } -}; -``` - -## JavaScript -```javascript -var largestRectangleArea = function(heights) { - let maxArea = 0 - const indexStack = [] - heights = [0, ...heights, 0] - - heights.forEach((height, i) => { - while (indexStack.length > 0 && height < heights[indexStack.at(-1)]) { - const poppedIndex = indexStack.pop() - - const poppedHeight = heights[poppedIndex] - const leftIndex = indexStack.at(-1) // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - const rightIndex = i // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - const width = rightIndex - leftIndex - 1 // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - const area = poppedHeight * width - if (area > maxArea) { - maxArea = area - } - } - - indexStack.push(i) - }) - - return maxArea -}; -``` - -## C# -```c# -public class Solution -{ - public int LargestRectangleArea(int[] heights) - { - int maxArea = 0; - var indexStack = new Stack(); - heights = [0, ..heights, 0]; - - for (var i = 0; i < heights.Length; i++) - { - while (indexStack.Count > 0 && heights[i] < heights[indexStack.Peek()]) - { - int poppedIndex = indexStack.Pop(); - - int poppedHeight = heights[poppedIndex]; - int leftIndex = indexStack.Peek(); // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - int rightIndex = i; // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - int width = rightIndex - leftIndex - 1; // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - int area = poppedHeight * width; - if (area > maxArea) - { - maxArea = area; - } - } - - indexStack.Push(i); - } - - return maxArea; - } -} -``` - -## Go -```go -func largestRectangleArea(heightSlice []int) int { - maxArea := 0 - indexStack := []int{} - heights := append([]int{0}, append(heightSlice, 0)...) - - for i, height := range heights { - for len(indexStack) > 0 && height < heights[indexStack[len(indexStack) - 1]] { - poppedIndex := indexStack[len(indexStack) - 1] - indexStack = indexStack[:len(indexStack) - 1] - - poppedHeight := heights[poppedIndex] - leftIndex := indexStack[len(indexStack) - 1] // poppedHeight's remaining left heights are all shorter than it, because when 'poppedHeight' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - rightIndex := i // poppedHeight's right heights (which are all taller than 'poppedHeight') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - width := rightIndex - leftIndex - 1 // So in the range of 'width', they are all no shorter than `poppedHeight`, although they have been popped out of the stack (disappeared). - - area := poppedHeight * width - if (area > maxArea) { - maxArea = area - } - } - - indexStack = append(indexStack, i) - } - - return maxArea -} -``` - -## Ruby -```ruby -def largest_rectangle_area(heights) - heights = [0] + heights + [0] - max_area = 0 - index_stack = [] - - heights.each_with_index do |height, i| - while !index_stack.empty? && height < heights[index_stack.last] - popped_index = index_stack.pop - - popped_height = heights[popped_index] - - left_index = index_stack[-1] # popped_height's remaining left heights are all shorter than 'popped_height', because when 'popped_height' itself was pushed into stack, it must have caused some (could be none) taller heights been popped out of the stack. - right_index = i # popped_height's right heights (which are all taller than 'popped_height') have been popped out of the stack (disappeared) when current `i` height is being pushed into stack. - width = right_index - left_index - 1 # So in the range of 'width', they are all no shorter than `popped_height`, although they have been popped out of the stack (disappeared). - - area = popped_height * width - max_area = area if area > max_area - end - - index_stack << i - end - - max_area -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1-1000/977-squares-of-a-sorted-array.md b/zh/1-1000/977-squares-of-a-sorted-array.md deleted file mode 100644 index 907d450..0000000 --- a/zh/1-1000/977-squares-of-a-sorted-array.md +++ /dev/null @@ -1,355 +0,0 @@ -# 977. 有序数组的平方 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[977. 有序数组的平方 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/977-squares-of-a-sorted-array),体验更佳! - -力扣链接:[977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array), 难度等级:**简单**。 - -## LeetCode “977. 有序数组的平方”问题描述 - -给你一个按 **非递减顺序** 排序的整数数组 `nums`,返回 **每个数字的平方** 组成的新数组,要求也按 **非递减顺序** 排序。 - -**进阶**:请你设计时间复杂度为 O(n) 的算法解决本问题。 - -### [示例 1] - -**输入**: `nums = [-4,-1,0,3,10]` - -**输出**: `[0,1,9,16,100]` - -**解释**: - -

平方后,数组变为 [16,1,0,9,100]
-排序后,数组变为 [0,1,9,16,100]

- - -### [示例 2] - -**输入**: `nums = [-7,-3,2,3,11]` - -**输出**: `[4,9,9,49,121]` - -### [约束] - -- `1 <= nums.length <= 10^4` -- `-10^4 <= nums[i] <= 10^4` -- `nums` 已按 **非递减顺序** 排序 - -## 思路 1 - -- 数组中最小的数位于数组内部,需要遍历才能找到,不太方便。 -- 但如果反向思考,能否更加方便地优先处理另外一些数呢?那么优先处理哪些数呢? - -
点击查看答案

答案是优先处理数组**两端**的数,因为它们最大。

- -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public int[] sortedSquares(int[] nums) { - var results = new int[nums.length]; - var left = 0; - var right = nums.length - 1; - var index = right; - - while (left <= right) { - if (Math.abs(nums[left]) <= nums[right]) { - results[index] = nums[right] * nums[right]; - right -= 1; - } else { - results[index] = nums[left] * nums[left]; - left += 1; - } - - index -= 1; - } - - return results; - } -} -``` - -## Python - -```python -class Solution: - def sortedSquares(self, nums: List[int]) -> List[int]: - results = [None] * len(nums) - left = 0 - right = index = len(nums) - 1 - - while left <= right: - if abs(nums[left]) <= nums[right]: - results[index] = nums[right] ** 2 - right -= 1 - else: - results[index] = nums[left] ** 2 - left += 1 - - index -= 1 - - return results -``` - -## C++ - -```cpp -class Solution { -public: - vector sortedSquares(vector& nums) { - auto results = vector(nums.size()); - auto left = 0; - int right = nums.size() - 1; // Should not use 'auto' here because 'auto' will make this variable become `unsigned long` which has no `-1`. - auto index = right; - - while (left <= right) { - if (abs(nums[left]) <= nums[right]) { - results[index] = nums[right] * nums[right]; - right -= 1; - } else { - results[index] = nums[left] * nums[left]; - left += 1; - } - - index -= 1; - } - - return results; - } -}; -``` - -## JavaScript - -```javascript -var sortedSquares = function (nums) { - const results = Array(nums.length).fill(null) - let left = 0 - let right = nums.length - 1 - let index = right - - while (left <= right) { - if (Math.abs(nums[left]) <= nums[right]) { - results[index] = nums[right] * nums[right] - right -= 1 - } else { - results[index] = nums[left] * nums[left] - left += 1 - } - - index -= 1 - } - - return results -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] SortedSquares(int[] nums) - { - var results = new int[nums.Length]; - int left = 0; - int right = nums.Length - 1; - int index = right; - - while (left <= right) - { - if (Math.Abs(nums[left]) <= nums[right]) - { - results[index] = nums[right] * nums[right]; - right -= 1; - } - else - { - results[index] = nums[left] * nums[left]; - left += 1; - } - - index -= 1; - } - - return results; - } -} -``` - -## Go - -```go -func sortedSquares(nums []int) []int { - results := make([]int, len(nums)) - left := 0 - right := len(nums) - 1 - index := right - - for left <= right { - if math.Abs(float64(nums[left])) <= float64(nums[right]) { - results[index] = nums[right] * nums[right] - right -= 1 - } else { - results[index] = nums[left] * nums[left] - left += 1 - } - - index -= 1 - } - - return results -} -``` - -## Ruby - -```ruby -def sorted_squares(nums) - results = Array.new(nums.length) - left = 0 - right = nums.size - 1 - index = right - - while left <= right - if nums[left].abs <= nums[right] - results[index] = nums[right] * nums[right] - right -= 1 - else - results[index] = nums[left] * nums[left] - left += 1 - end - - index -= 1 - end - - results -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - - - -## 复杂度 - -- 时间复杂度: `O(N * log N)`. -- 空间复杂度: `O(N)`. - -## Java - -```java -class Solution { - public int[] sortedSquares(int[] nums) { - for (var i = 0; i < nums.length; i++) { - nums[i] *= nums[i]; - } - - Arrays.sort(nums); - - return nums; - } -} -``` - -## Python - -```python -class Solution: - def sortedSquares(self, nums: List[int]) -> List[int]: - results = [num ** 2 for num in nums] - - results.sort() - - return results -``` - -## C++ - -```cpp -class Solution { -public: - vector sortedSquares(vector& nums) { - for (auto i = 0; i < nums.size(); i++) { - nums[i] *= nums[i]; - } - - sort(nums.begin(), nums.end()); - - return nums; - } -}; -``` - -## JavaScript - -```javascript -var sortedSquares = function (nums) { - return _.sortBy( - nums.map((num) => num * num) - ) -}; -``` - -## C# - -```csharp -public class Solution -{ - public int[] SortedSquares(int[] nums) - { - for (int i = 0; i < nums.Length; i++) - nums[i] *= nums[i]; - - Array.Sort(nums); - - return nums; - } -} -``` - -## Go - -```go -func sortedSquares(nums []int) []int { - for i, _ := range nums { - nums[i] *= nums[i] - } - - sort.Sort(sort.IntSlice(nums)) - - return nums -} -``` - -## Ruby - -```ruby -def sorted_squares(nums) - nums.map { |num| num ** 2 }.sort -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[977. 有序数组的平方 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/977-squares-of-a-sorted-array). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1001-2000/1035-uncrossed-lines.md b/zh/1001-2000/1035-uncrossed-lines.md deleted file mode 100644 index caffe02..0000000 --- a/zh/1001-2000/1035-uncrossed-lines.md +++ /dev/null @@ -1,221 +0,0 @@ -# 1035. Uncrossed Lines -LeetCode link: [1035. Uncrossed Lines](https://leetcode.com/problems/uncrossed-lines/) - -## LeetCode problem description -You are given two integer arrays `nums1` and `nums2`. We write the integers of `nums1` and `nums2` (in the order they are given) on two separate horizontal lines. - -We may draw connecting lines: a straight line connecting two numbers `nums1[i]` and `nums2[j]` such that: - -* `nums1[i]` == `nums2[j]`, and -* the line we draw does not intersect any other connecting (non-horizontal) line. - -Note that a connecting line cannot intersect even at the endpoints (i.e., each number can only belong to one connecting line). - -Return the maximum number of connecting lines we can draw in this way. - -``` -------------------------------------------------------------------------------------------------------------------------------------------- -[Example 1] - -Input: nums1 = [1,4,2], nums2 = [1,2,4] -Output: 2 -Explanation: We can draw 2 uncrossed lines as in the diagram. -We cannot draw 3 uncrossed lines, because the line from nums1[1] = 4 to nums2[2] = 4 will intersect the line from nums1[2]=2 to nums2[1]=2. -------------------------------------------------------------------------------------------------------------------------------------------- -[Example 2] - -Input: nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2] -Output: 3 -------------------------------------------------------------------------------------------------------------------------------------------- -[Example 3] - -Input: nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1] -Output: 2 -------------------------------------------------------------------------------------------------------------------------------------------- -[Constraints] - -1 <= nums1.length, nums2.length <= 500 -1 <= nums1[i], nums2[j] <= 2000 -------------------------------------------------------------------------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Python -```python -# Example of a 2D 'dp' array: -# nums1 = [ 2, 5, 1, 2, 5] -# nums2 = [10, 5, 2, 1, 5, 2] -# 10 5 2 1 5 2 -# 0 0 0 0 0 0 0 -# 2 0 0 0 1 1 1 1 -# 5 0 0 1 1 1 2 2 -# 1 0 ... -# 2 0 ... -# 5 0 ... -class Solution: - def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int: - dp = [[0] * (len(nums2) + 1) for _ in range(len(nums1) + 1)] - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if nums1[i - 1] == nums2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - else: - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) - - return dp[-1][-1] -``` - -## Java -```java -class Solution { - public int maxUncrossedLines(int[] nums1, int[] nums2) { - var dp = new int[nums1.length + 1][nums2.length + 1]; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# -```c# -public class Solution -{ - public int MaxUncrossedLines(int[] nums1, int[] nums2) - { - var dp = new int[nums1.Length + 1, nums2.Length + 1]; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (nums1[i - 1] == nums2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1] + 1; - } - else - { - dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]); - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## C++ -```cpp -class Solution { -public: - int maxUncrossedLines(vector& nums1, vector& nums2) { - vector> dp(nums1.size() + 1, vector(nums2.size() + 1)); - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (nums1[i - 1] == nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript -```javascript -var maxUncrossedLines = function(nums1, nums2) { - const dp = Array(nums1.length + 1).fill().map( - () => Array(nums2.length + 1).fill(0) - ) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (nums1[i - 1] === nums2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go -```go -func maxUncrossedLines(nums1 []int, nums2 []int) int { - dp := make([][]int, len(nums1) + 1) - for i := range dp { - dp[i] = make([]int, len(nums2) + 1) - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if nums1[i - 1] == nums2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby -```ruby -def max_uncrossed_lines(nums1, nums2) - dp = Array.new(nums1.size + 1) do - Array.new(nums2.size + 1, 0) - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if nums1[i - 1] == nums2[j - 1] - dp[i - 1][j - 1] + 1 - else - [ dp[i][j - 1], dp[i - 1][j] ].max - end - end - end - - dp[-1][-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1049-last-stone-weight-ii.md b/zh/1001-2000/1049-last-stone-weight-ii.md deleted file mode 100644 index 290c7ad..0000000 --- a/zh/1001-2000/1049-last-stone-weight-ii.md +++ /dev/null @@ -1,598 +0,0 @@ -# 1049. 最后一块石头的重量 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[1049. 最后一块石头的重量 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1049-last-stone-weight-ii),体验更佳! - -力扣链接:[1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii), 难度等级:**中等**。 - -## LeetCode “1049. 最后一块石头的重量 II”问题描述 - -有一堆石头,用整数数组 `stones` 表示。其中 `stones[i]` 表示第 `i` 块石头的重量。 - -每一回合,从中选出**任意两块石头**,然后将它们一起粉碎。假设石头的重量分别为 `x` 和 `y`,且 `x <= y`。那么粉碎的可能结果如下: - -- 如果 `x == y`,那么两块石头都会被完全粉碎; -- 如果 `x != y`,那么重量为 `x` 的石头将会完全粉碎,而重量为 `y` 的石头新重量为 `y-x`。 - -最后,**最多只会剩下一块** 石头。返回此石头 **最小的可能重量** 。如果没有石头剩下,就返回 `0`。 - -### [示例 1] - -**输入**: `stones = [2,7,4,1,8,1]` - -**输出**: `1` - -**解释**: - -

组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
-组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
-组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
-组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。

- - -### [示例 2] - -**输入**: `stones = [31,26,33,21,40]` - -**输出**: `5` - -### [约束] - -1 <= stones.length <= 30 -1 <= stones[i] <= 100 - -### [Hints] - -
- 提示 1 - Think of the final answer as a sum of weights with + or - sign symbols in front of each weight. Actually, all sums with 1 of each sign symbol are possible. - - -
- -
- 提示 2 - Use dynamic programming: for every possible sum with N stones, those sums +x or -x is possible with N+1 stones, where x is the value of the newest stone. (This overcounts sums that are all positive or all negative, but those don't matter.) - - -
- -## 思路 1 - -- 这道题可以用蛮力法解决,就是找出数组所有的子集,看每个子集数组的和是否接近完整数组和的一半,找最接近的那个。但是当我们看到`stones.length <= 30`的时候,我们就知道这样的解法一定会超时。 -- 所以我们需要换个思路,你之前的题目相当于求拆分后两个数组和的最小差值,如果找到一个子集数组,它的和最接近完整数组和的一半,那么它就是我们想要的子集数组。 -- 那么这道题就变成了`0/1背包问题`。 - -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## “0/1背包问题”的模式 - -典型的“0/1背包问题”,指每个“物品”只能使用一次,来填充“背包”。“物品”有“重量”和“价值”属性,求“背包”能存放的“物品”的最大价值。 - -其特点是:有**一组数字**,每个数字只能被使用一次,通过某种计算得到**另一个数字**。问题也可以变成能否得到?有多少种变化?等。 - -因为“0/1背包问题”属于“动态规划”,所以我会用“动态规划”的模式讲解。 - -1. 确定数组`dp`的每个值代表的含义。 - - 首选**一维滚动数组**,代码简洁。 - - 确定什么是“物品”,什么是“背包”。 - - 如果`dp[j]`是一个布尔值,则`dp[j]`表示是否可以前`i`个`物品`的`和`得到`j`。 - - 如果`dp[j]`是一个数值,则`dp[j]`表示是利用前`i`个`物品`,`dp[j]`能达到的所求问题的极限值。 -2. 初始化数组`dp`的值。 - - 确定“背包”的大小。需要让背包大小再加1,即插入`dp[0]`做为起始点,方便理解和引用。 - - `dp[0]`有时需要特殊处理。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - 先在外层循环中,**遍历物品**。 - - 后在内层循环中,**遍历背包大小**。 - - 在遍历背包大小时,由于`dp[j]`取决于`dp[j]`和`dp[j - weights[i]]`,因此我们应该**从右到左**遍历`dp`数组。 - - 请思考是否可以从`从左到右`遍历`dp`数组? -4. 根据`dp`网格数据,推导出“递推公式”。 - - 如果`dp[j]`是一个布尔值: - - ```cpp - dp[j] = dp[j] || dp[j - weights[i]] - ``` - - 如果`dp[j]`是一个数值: - - ```cpp - dp[j] = min_or_max(dp[j], dp[j - weights[i]] + values[i]) - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 步骤 - -1. 确定`dp[j]`的**含义** - - `dp[j]`表示是否可以用前`i`个`stones`的`和`得到`j`。 - - `dp[j]`是一个布尔值。 -2. 确定 `dp` 数组的初始值 - - 举个例子: - - ``` - stones = [2,7,4,1,8,1],所以 '总和的一半' 是 11。 - 背包的 `size` 就是 '11 + 1',‘物品’ 是 'stones'。 - 所以初始化后,'dp' 数组将是: - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F # dp - # 2 - # 7 - # 4 - # 1 - # 8 - # 1 - ``` - - `dp[0]` 设为 `true`,表示不使用任何 `stones` 也可以得到一个空背包。另外,它作为起始值,后面的 `dp[j]` 将依赖于它。如果它是 `false`,则 `dp[j]` 的所有值都将为 `false`。 - - `dp[j] = false (j != 0)`,表示不使用 `stones` 就不可能得到 `j`。 -3. 根据一个示例,“按顺序”填入`dp`网格数据。 - - ``` - 1. 使用第一块石头 '2'。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 2 T F T F F F F F F F F F # dp - ``` - ``` - 2. 使用第二颗石头“7”。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 2 T F T F F F F F F F F F - # 7 T F T F F F F T F T F F - ``` - ``` - 3. 使用第三颗石头“4”。 - # 0 1 2 3 4 5 6 7 8 9 10 11 - # T F F F F F F F F F F F - # 2 T F T F F F F F F F F F - # 7 T F T F F F F F T F F F - # 4 T F T F T F T T F T F T # dp - # ... - ``` -4. 根据`dp`网格数据,推导出“递推公式”。 - - ```cpp - dp[j] = dp[j] || dp[j - stones[i]] - ``` -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -## 复杂度 - -- 时间复杂度: `O(n * sum/2)`. -- 空间复杂度: `O(sum/2)`. - -## Python - -```python -class Solution: - def lastStoneWeightII(self, stones: List[int]) -> int: - sum_ = sum(stones) - - dp = [False] * (sum_ // 2 + 1) - dp[0] = True - - for stone in stones: - # If not traversing in reverse order, the newly assigned value `dp[j]` will act as `dp[j - stone]` later, - # then the subsequent `dp[j]` will be affected. But each `stone` can only be used once! - for j in range(len(dp) - 1, 0, -1): - if j < stone: - break - dp[j] = dp[j] or dp[j - stone] - - for i in range(len(dp) - 1, -1, -1): - if dp[i]: - return sum_ - i * 2 -``` - -## C# - -```csharp -public class Solution { - public int LastStoneWeightII(int[] stones) { - var sum = stones.Sum(); - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (int stone in stones) { - for (var j = dp.GetUpperBound(0); j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone]; - } - } - - for (var j = dp.GetUpperBound(0); j >= 0; j--) { - if (dp[j]) { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - int lastStoneWeightII(vector& stones) { - auto sum = reduce(stones.begin(), stones.end()); - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto stone : stones) { - for (auto j = dp.size() - 1; j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone]; - } - } - - for (auto i = dp.size() - 1; i >= 0; i--) { - if (dp[i]) { - return sum - i * 2; - } - } - - throw logic_error("lastStoneWeightII() has a logical error!"); - } -}; -``` - -## Java - -```java -class Solution { - public int lastStoneWeightII(int[] stones) { - var sum = IntStream.of(stones).sum(); - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var stone : stones) { - for (var j = dp.length - 1; j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone]; - } - } - - for (var j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## JavaScript - -```javascript -var lastStoneWeightII = function (stones) { - const sum = _.sum(stones) - - const dp = Array(Math.floor(sum / 2) + 1).fill(false) - dp[0] = true - - for (const stone of stones) { - for (let j = dp.length - 1; j >= stone; j--) { - dp[j] = dp[j] || dp[j - stone] - } - } - - for (let j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2 - } - } -}; -``` - -## Go - -```go -func lastStoneWeightII(stones []int) int { - sum := 0 - for _, stone := range stones { - sum += stone - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, stone := range stones { - for j := len(dp) - 1; j >= stone; j-- { - dp[j] = dp[j] || dp[j - stone] - } - } - - for j := len(dp) - 1; j >= 0; j-- { - if dp[j] { - return sum - j * 2 - } - } - - return -1 // This line should be unreachable. It represents function has a logical error. -} -``` - -## Ruby - -```ruby -def last_stone_weight_ii(stones) - sum = stones.sum - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - stones.each do |stone| - (1...dp.size).reverse_each do |j| - break if j < stone - - dp[j] = dp[j] || dp[j - stone] - end - end - - (0...dp.size).reverse_each do |j| - return sum - j * 2 if dp[j] - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## 思路 2 - -在*方案 1*中,遍历顺序是 **从右到左**,这真的很重要。 - -面试的时候,你需要记住它。有什么办法可以不用担心遍历顺序? - -
点击查看答案

只要把原`dp`复制一份,并引用复制品的值,就不用担心原`dp`值被修改了。

- -## 复杂度 - -- 时间复杂度: `O(n * sum/2)`. -- 空间复杂度: `O(n * sum/2)`. - -## Python - -```python -class Solution: - def lastStoneWeightII(self, stones: List[int]) -> int: - sum_ = sum(stones) - - dp = [False] * (sum_ // 2 + 1) - dp[0] = True - - for stone in stones: - dc = dp.copy() - - for j in range(stone, len(dp)): - dp[j] = dc[j] or dc[j - stone] - - for i in range(len(dp) - 1, -1, -1): - if dp[i]: - return sum_ - i * 2 -``` - -## C# - -```csharp -public class Solution -{ - public int LastStoneWeightII(int[] stones) - { - int sum = stones.Sum(); - - var dp = new bool[sum / 2 + 1]; - dp[0] = true; - - foreach (int stone in stones) - { - var dc = (bool[]) dp.Clone(); - - for (var j = stone; j < dp.Length; j++) - { - dp[j] = dc[j] || dc[j - stone]; - } - } - - for (var j = dp.GetUpperBound(0); j >= 0; j--) - { - if (dp[j]) - { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - int lastStoneWeightII(vector& stones) { - auto sum = reduce(stones.begin(), stones.end()); - - auto dp = vector(sum / 2 + 1); - dp[0] = true; - - for (auto stone : stones) { - auto dc = dp; - - for (auto j = stone; j < dp.size(); j++) { - dp[j] = dc[j] || dc[j - stone]; - } - } - - for (auto i = dp.size() - 1; i >= 0; i--) { - if (dp[i]) { - return sum - i * 2; - } - } - - throw logic_error("lastStoneWeightII() has a logical error!"); - } -}; -``` - -## Java - -```java -class Solution { - public int lastStoneWeightII(int[] stones) { - var sum = IntStream.of(stones).sum(); - - var dp = new boolean[sum / 2 + 1]; - dp[0] = true; - - for (var stone : stones) { - var dc = dp.clone(); - - for (var j = stone; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - stone]; - } - } - - for (var j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2; - } - } - - throw new ArithmeticException("lastStoneWeightII() has a logical error!"); - } -} -``` - -## JavaScript - -```javascript -var lastStoneWeightII = function (stones) { - const sum = _.sum(stones) - - const dp = Array(Math.floor(sum / 2) + 1).fill(false) - dp[0] = true - - for (const stone of stones) { - const dc = [...dp] - - for (let j = stone; j < dp.length; j++) { - dp[j] = dc[j] || dc[j - stone] - } - } - - for (let j = dp.length - 1; j >= 0; j--) { - if (dp[j]) { - return sum - j * 2 - } - } -}; -``` - -## Go - -```go -func lastStoneWeightII(stones []int) int { - sum := 0 - for _, stone := range stones { - sum += stone - } - - dp := make([]bool, sum / 2 + 1) - dp[0] = true - - for _, stone := range stones { - dc := slices.Clone(dp) - - for j := stone; j < len(dp); j++ { - dp[j] = dc[j] || dc[j - stone] - } - } - - for j := len(dp) - 1; j >= 0; j-- { - if dp[j] { - return sum - j * 2 - } - } - - return -1 // This line should be unreachable. It represents function has a logical error. -} -``` - -## Ruby - -```ruby -def last_stone_weight_ii(stones) - sum = stones.sum - - dp = Array.new(sum / 2 + 1, false) - dp[0] = true - - stones.each do |stone| - dc = dp.clone - - (stone...dp.size).each do |j| - dp[j] = dc[j] || dc[j - stone] - end - end - - (0...dp.size).reverse_each do |j| - return sum - j * 2 if dp[j] - end -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[1049. 最后一块石头的重量 II - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1049-last-stone-weight-ii). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1001-2000/1071-greatest-common-divisor-of-strings.md b/zh/1001-2000/1071-greatest-common-divisor-of-strings.md deleted file mode 100644 index 1529810..0000000 --- a/zh/1001-2000/1071-greatest-common-divisor-of-strings.md +++ /dev/null @@ -1,264 +0,0 @@ -# 1071. 字符串的最大公因子 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[1071. 字符串的最大公因子 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1071-greatest-common-divisor-of-strings),体验更佳! - -力扣链接:[1071. 字符串的最大公因子](https://leetcode.cn/problems/greatest-common-divisor-of-strings), 难度等级:**简单**。 - -## LeetCode “1071. 字符串的最大公因子”问题描述 - -对于字符串 `s` 和 `t`,只有在 `s = t + t + t + ... + t + t`(`t` 自身连接 `1` 次或多次)时,我们才认定 “`t` 能除尽 `s`”。 - -给定两个字符串 `str1` 和 `str2` 。返回 最长字符串 `x`,要求满足 `x` 能除尽 `str1` 且 `x` 能除尽 `str2` 。 - -### [示例 1] - -**输入**: `str1 = "ABCABC", str2 = "ABC"` - -**输出**: `"ABC"` - -### [示例 2] - -**输入**: `str1 = "ABABAB", str2 = "ABAB"` - -**输出**: `"AB"` - -### [示例 3] - -**输入**: `str1 = "LEET", str2 = "CODE"` - -**输出**: `""` - -### [约束] - -- `1 <= str1.length, str2.length <= 1000` -- `str1` 和 `str2` 由大写英文字母组成 - -### [Hints] - -
- 提示 1 - The greatest common divisor must be a prefix of each string, so we can try all prefixes. - - -
- -## 思路 - -- 最大公约数一定是每个字符串的前缀,所以我们可以尝试所有前缀。 - -- 枚举所有可能的前缀,判断该前缀重复若干次后能否等于原字符串。 - -- 返回最长的那个。 - -## 步骤 - -1. 取两个字符串的最小长度 `min_size`。 -2. 从长度 `1` 到 `min_size`,依次枚举前缀 `candidate`。 -3. 如果 `candidate` 的长度能同时整除 `str1` 和 `str2` 的长度,且 `candidate` 重复相应次数后等于 `str1` 和 `str2`,则更新结果。 -4. 最后返回最长的满足条件的 `candidate`。 - -## 复杂度 - -- 时间复杂度: `O(N * (N + M))`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def gcdOfStrings(self, str1: str, str2: str) -> str: - result = "" - min_size = min(len(str1), len(str2)) - - for i in range(1, min_size + 1): - if len(str1) % i == 0 and len(str2) % i == 0: - candidate = str1[:i] - - if candidate * (len(str1) // i) == str1 and candidate * (len(str2) // i) == str2: - result = candidate - - return result -``` - -## Java - -```java -class Solution { - public String gcdOfStrings(String str1, String str2) { - String result = ""; - int minSize = Math.min(str1.length(), str2.length()); - - for (int i = 1; i <= minSize; i++) { - if (str1.length() % i == 0 && str2.length() % i == 0) { - String candidate = str1.substring(0, i); - if (isValid(candidate, str1) && isValid(candidate, str2)) { - result = candidate; - } - } - } - - return result; - } - - private boolean isValid(String candidate, String s) { - int count = s.length() / candidate.length(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < count; i++) { - sb.append(candidate); - } - return sb.toString().equals(s); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string gcdOfStrings(string str1, string str2) { - string result; - int min_size = min(str1.size(), str2.size()); - - for (int i = 1; i <= min_size; i++) { - if (str1.size() % i == 0 && str2.size() % i == 0) { - string candidate = str1.substr(0, i); - if (isValid(candidate, str1) && isValid(candidate, str2)) { - result = candidate; - } - } - } - - return result; - } - -private: - bool isValid(const string& candidate, const string& s) { - int count = s.size() / candidate.size(); - string temp; - for (int i = 0; i < count; i++) { - temp += candidate; - } - return temp == s; - } -}; -``` - -## C# - -```csharp -public class Solution -{ - public string GcdOfStrings(string str1, string str2) - { - string result = ""; - int minSize = Math.Min(str1.Length, str2.Length); - - for (int i = 1; i <= minSize; i++) - { - if (str1.Length % i == 0 && str2.Length % i == 0) - { - string candidate = str1.Substring(0, i); - if (IsValid(candidate, str1) && IsValid(candidate, str2)) - { - result = candidate; - } - } - } - - return result; - } - - private bool IsValid(string candidate, string s) - { - return string.Concat(Enumerable.Repeat(candidate, s.Length / candidate.Length)) == s; - } -} -``` - -## JavaScript - -```javascript -var gcdOfStrings = function (str1, str2) { - let result = ""; - const minSize = Math.min(str1.length, str2.length); - - const isValid = (candidate, s) => { - return candidate.repeat(s.length / candidate.length) === s; - }; - - for (let i = 1; i <= minSize; i++) { - if (str1.length % i === 0 && str2.length % i === 0) { - const candidate = str1.substring(0, i); - if (isValid(candidate, str1) && isValid(candidate, str2)) { - result = candidate; - } - } - } - - return result; -} - -``` - -## Go - -```go -func gcdOfStrings(str1 string, str2 string) string { - result := "" - minSize := len(str1) - if len(str2) < minSize { - minSize = len(str2) - } - - for i := 1; i <= minSize; i++ { - if len(str1) % i == 0 && len(str2) % i == 0 { - candidate := str1[:i] - if isValid(candidate, str1) && isValid(candidate, str2) { - result = candidate - } - } - } - - return result -} - -func isValid(candidate, s string) bool { - return strings.Repeat(candidate, len(s)/len(candidate)) == s -} -``` - -## Ruby - -```ruby -def gcd_of_strings(str1, str2) - result = "" - min_size = [ str1.size, str2.size ].min - - (1..min_size).each do |i| - next unless (str1.size % i).zero? && (str2.size % i).zero? - - candidate = str1[0...i] - next unless candidate * (str1.size / i) == str1 - next unless candidate * (str2.size / i) == str2 - - result = candidate - end - - result -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[1071. 字符串的最大公因子 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1071-greatest-common-divisor-of-strings). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1001-2000/1143-longest-common-subsequence.md b/zh/1001-2000/1143-longest-common-subsequence.md deleted file mode 100644 index 48a2da8..0000000 --- a/zh/1001-2000/1143-longest-common-subsequence.md +++ /dev/null @@ -1,227 +0,0 @@ -# 1143. Longest Common Subsequence -LeetCode link: [1143. Longest Common Subsequence](https://leetcode.com/problems/longest-common-subsequence/) - -## LeetCode problem description -Given two strings `text1` and `text2`, return the length of their longest **common subsequence**. If there is no common subsequence, return `0`. - -A `subsequence` of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters. - -* For example, `"ace"` is a subsequence of `"abcde"`. - -A **common subsequence** of two strings is a subsequence that is common to both strings. - -``` ----------------------------------------------------------------------------- -[Example 1] - -Input: text1 = "abcde", text2 = "ace" -Output: 3 -Explanation: The longest common subsequence is "ace" and its length is 3. ----------------------------------------------------------------------------- -[Example 2] - -Input: text1 = "abc", text2 = "abc" -Output: 3 -Explanation: The longest common subsequence is "abc" and its length is 3. ----------------------------------------------------------------------------- -[Example 3] - -Input: text1 = "abc", text2 = "def" -Output: 0 -Explanation: There is no such common subsequence, so the result is 0. ----------------------------------------------------------------------------- -[Constraints] - -1 <= text1.length, text2.length <= 1000 -text1 and text2 consist of only lowercase English characters. ----------------------------------------------------------------------------- -``` - -## Thoughts -This problem can be solved using **Dynamic programming**. - -Detailed solutions will be given later, and now only the best practices in 7 languages are given. - -### Complexity -* Time: `O(n * m)`. -* Space: `O(n * m)`. - -## Java -```java -// Example of a 2D 'dp' array: -// a c e -// 0 0 0 0 -// a 0 1 1 1 -// b 0 1 1 1 -// c 0 1 2 2 -// d 0 1 2 2 -// e 0 1 2 3 -class Solution { - public int longestCommonSubsequence(String text1, String text2) { - var dp = new int[text1.length() + 1][text2.length() + 1]; - - for (var i = 1; i < dp.length; i++) { - for (var j = 1; j < dp[0].length; j++) { - if (text1.charAt(i - 1) == text2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.length - 1][dp[0].length - 1]; - } -} -``` - -## C# -```c# -public class Solution -{ - public int LongestCommonSubsequence(string text1, string text2) - { - var dp = new int[text1.Length + 1, text2.Length + 1]; - - for (var i = 1; i < dp.GetLength(0); i++) - { - for (var j = 1; j < dp.GetLength(1); j++) - { - if (text1[i - 1] == text2[j - 1]) - { - dp[i, j] = dp[i - 1, j - 1] + 1; - } - else - { - dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]); - } - } - } - - return dp[dp.GetUpperBound(0), dp.GetUpperBound(1)]; - } -} -``` - -## Python -```python -# Example of a 2D 'dp' array: -# a b f k m a j b -# 0 0 0 0 0 0 0 0 0 -# a 0 1 1 1 1 1 1 1 1 -# j 0 1 1 1 1 1 1 2 2 -# f 0 1 1 2 2 2 2 2 2 -# b 0 1 2 2 2 2 2 2 2 -# m 0 1 2 2 2 3 3 3 3 -# k 0 1 2 2 2 3 3 3 3 -# j 0 1 2 2 2 3 3 4 4 -class Solution: - def longestCommonSubsequence(self, text1: str, text2: str) -> int: - dp = [[0] * (len(text2) + 1) for _ in range(len(text1) + 1)] - - for i in range(1, len(dp)): - for j in range(1, len(dp[0])): - if text1[i - 1] == text2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - else: - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) - - return dp[-1][-1] -``` - -## C++ -```cpp -class Solution { -public: - int longestCommonSubsequence(string text1, string text2) { - vector> dp(text1.size() + 1, vector(text2.size() + 1)); - - for (auto i = 1; i < dp.size(); i++) { - for (auto j = 1; j < dp[0].size(); j++) { - if (text1[i - 1] == text2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp[dp.size() - 1][dp[0].size() - 1]; - } -}; -``` - -## JavaScript -```javascript -var longestCommonSubsequence = function (text1, text2) { - const dp = Array(text1.length + 1).fill().map( - () => Array(text2.length + 1).fill(0) - ) - - for (let i = 1; i < dp.length; i++) { - for (let j = 1; j < dp[0].length; j++) { - if (text1[i - 1] === text2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) - } - } - } - - return dp.at(-1).at(-1) -}; -``` - -## Go -```go -func longestCommonSubsequence(text1 string, text2 string) int { - dp := make([][]int, len(text1) + 1) - for i := range dp { - dp[i] = make([]int, len(text2) + 1) - } - - for i := 1; i < len(dp); i++ { - for j := 1; j < len(dp[0]); j++ { - if text1[i - 1] == text2[j - 1] { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) - } - } - } - - return dp[len(dp) - 1][len(dp[0]) - 1] -} -``` - -## Ruby -```ruby -def longest_common_subsequence(text1, text2) - dp = Array.new(text1.size + 1) do - Array.new(text2.size + 1, 0) - end - - (1...dp.size).each do |i| - (1...dp[0].size).each do |j| - dp[i][j] = - if text1[i - 1] == text2[j - 1] - dp[i - 1][j - 1] + 1 - else - [ dp[i][j - 1], dp[i - 1][j] ].max - end - end - end - - dp[-1][-1] -end -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md b/zh/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md deleted file mode 100644 index de70fd9..0000000 --- a/zh/1001-2000/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.md +++ /dev/null @@ -1,146 +0,0 @@ -# 1334. 阈值距离内邻居最少的城市 - 力扣题解最佳实践 -力扣链接:[1334. 阈值距离内邻居最少的城市](https://leetcode.cn/problems/find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance) ,难度:**中等**。 - -## 力扣“1334. 阈值距离内邻居最少的城市”问题描述 -有 `n` 个城市,按从 `0` 到 `n-1` 编号。给你一个边数组 `edges`,其中 `edges[i] = [fromi, toi, weighti]` 代表 `from_i` 和 `to_i` 两个城市之间的双向加权边,距离阈值是一个整数 `distanceThreshold`。 - -返回在路径距离限制为 `distanceThreshold` 以内可到达城市最少的城市。如果有多个这样的城市,则返回编号**最大**的城市。 - -注意,连接城市 _**i**_ 和 _**j**_ 的路径的距离等于沿该路径的所有边的权重之和。 - -### [示例 1] -![](../../images/examples/1334_1.png) - -**输入**: `n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4` - -**输出**: `3` - -**解释**: -``` -城市分布图如上。 -每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是: -城市 0 -> [城市 1, 城市 2] -城市 1 -> [城市 0, 城市 2, 城市 3] -城市 2 -> [城市 0, 城市 1, 城市 3] -城市 3 -> [城市 1, 城市 2] -城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。 -``` - -### [示例 2] -![](../../images/examples/1334_2.png) - -**输入**: `n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2` - -**输出**: `0` - -**解释**: -``` -城市分布图如上。 -每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是: -城市 0 -> [城市 1] -城市 1 -> [城市 0, 城市 4] -城市 2 -> [城市 3, 城市 4] -城市 3 -> [城市 2, 城市 4] -城市 4 -> [城市 1, 城市 2, 城市 3] -城市 0 在阈值距离 2 以内只有 1 个邻居城市。 -``` - -### [约束] -- `2 <= n <= 100` -- `1 <= edges.length <= n * (n - 1) / 2` -- `edges[i].length == 3` -- `0 <= from_i < to_i < n` -- `1 <= weight_i, distanceThreshold <= 10^4` -- 所有 `(from_i, to_i)` 都是不同的。 - -### [提示] -
- 提示 1 - Use Floyd-Warshall's algorithm to compute any-point to any-point distances. (Or can also do Dijkstra from every node due to the weights are non-negative). -
- -
- 提示 2 - For each city calculate the number of reachable cities within the threshold, then search for the optimal city. -
- -## Intuition -就像`提示`据说的,你可以使用 **Floyd-Warshall 算法** 计算任意两点之间的最短距离。 - -或者,你可以多次调用 **Dijkstra 算法**,每次调用时用不同的城市做为`起始城市`。 - -或者,你可以多次调用 **集合优化的 Bellman-Ford 算法**,每次调用时用不同的城市做为`起始城市`。 - -## Complexity -* Time: `O(N^3)`. -* Space: `O(N^2)`. - -## Python -```python -class Solution: - def findTheCity(self, n: int, edges: List[List[int]], distance_threshold: int) -> int: - dp = [] - - for i in range(n): - dp.append([float('inf')] * n) - dp[i][i] = 0 - - for i, j, weight in edges: - dp[i][j] = weight - dp[j][i] = weight - - for k in range(n): - for i in range(n): - for j in range(n): - dp[i][j] = min( - dp[i][j], - dp[i][k] + dp[k][j], - ) - - result = -1 - min_count = float('inf') - - for i, row in enumerate(dp): - count = len([distance for distance in row if distance <= distance_threshold]) - - if count <= min_count: - min_count = count - result = i - - return result -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1431-kids-with-the-greatest-number-of-candies.md b/zh/1001-2000/1431-kids-with-the-greatest-number-of-candies.md deleted file mode 100644 index 2324549..0000000 --- a/zh/1001-2000/1431-kids-with-the-greatest-number-of-candies.md +++ /dev/null @@ -1,189 +0,0 @@ -# 1431. 拥有最多糖果的孩子 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[1431. 拥有最多糖果的孩子 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1431-kids-with-the-greatest-number-of-candies),体验更佳! - -力扣链接:[1431. 拥有最多糖果的孩子](https://leetcode.cn/problems/kids-with-the-greatest-number-of-candies), 难度等级:**简单**。 - -## LeetCode “1431. 拥有最多糖果的孩子”问题描述 - -有 `n` 个有糖果的孩子。给你一个数组 `candies`,其中 `candies[i]` 代表第 `i` 个孩子拥有的糖果数目,和一个整数 `extraCandies` 表示你所有的额外糖果的数量。 - -返回一个长度为 `n` 的布尔数组 `result`,如果把所有的 `extraCandies` 给第 `i` 个孩子之后,他会拥有所有孩子中 **最多** 的糖果,那么 `result[i]` 为 `true`,否则为 `false`。 - -注意,允许有多个孩子同时拥有 **最多** 的糖果数目。 - -### [示例 1] - -**输入**: `candies = [2,3,5,1,3], extraCandies = 3` - -**输出**: `[true,true,true,false,true]` - -**解释**: - -

如果你把额外的糖果全部给:
-孩子 1,将有 2 + 3 = 5 个糖果,是孩子中最多的。
-孩子 2,将有 3 + 3 = 6 个糖果,是孩子中最多的。
-孩子 3,将有 5 + 3 = 8 个糖果,是孩子中最多的。
-孩子 4,将有 1 + 3 = 4 个糖果,不是孩子中最多的。
-孩子 5,将有 3 + 3 = 6 个糖果,是孩子中最多的。

- - -### [示例 2] - -**输入**: `candies = [4,2,1,1,2], extraCandies = 1` - -**输出**: `[true,false,false,false,false]` - -**解释**: `只有 1 个额外糖果,所以不管额外糖果给谁,只有孩子 1 可以成为拥有糖果最多的孩子。` - -### [示例 3] - -**输入**: `candies = [12,1,12], extraCandies = 10` - -**输出**: `[true,false,true]` - -### [约束] - -- `n == candies.length` -- `2 <= n <= 100` -- `1 <= candies[i] <= 100` -- `1 <= extraCandies <= 50` - -### [Hints] - -
- 提示 1 - For each kid check if candies[i] + extraCandies ≥ maximum in Candies[i]. - - -
- -## 思路 - -1. 找出所有孩子中最多的糖果数 -2. 检查每个孩子拿到额外糖果后能否达到或超过这个数 - -## 步骤 - -1. `max_candy = candies.max` → 直接取数组最大值 -2. `candies.map { |candy| candy + extra_candy >= max_candy }` → 用map遍历,计算每个孩子是否能达到最多 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def kidsWithCandies(self, candies: List[int], extra_candy: int) -> List[bool]: - max_candy = max(candies) - result = [] - - for candy in candies: - result.append(candy + extra_candy >= max_candy) - - return result -``` - -## Java - -```java -class Solution { - public List kidsWithCandies(int[] candies, int extraCandy) { - int maxCandy = Arrays.stream(candies).max().getAsInt(); - List result = new ArrayList<>(); - - for (int candy : candies) { - result.add(candy + extraCandy >= maxCandy); - } - - return result; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - vector kidsWithCandies(vector& candies, int extraCandy) { - int max_candy = *max_element(candies.begin(), candies.end()); - vector result; - - for (int candy : candies) { - result.push_back(candy + extraCandy >= max_candy); - } - - return result; - } -}; -``` - -## JavaScript - -```javascript -var kidsWithCandies = function(candies, extraCandy) { - const maxCandy = Math.max(...candies) - return candies.map((candy) => candy + extraCandy >= maxCandy) -}; - -``` - -## Go - -```go -func kidsWithCandies(candies []int, extraCandy int) []bool { - maxCandy := candies[0] - for _, candy := range candies { - if candy > maxCandy { - maxCandy = candy - } - } - - result := make([]bool, len(candies)) - for i, candy := range candies { - result[i] = candy+extraCandy >= maxCandy - } - - return result -} -``` - -## C# - -```csharp -public class Solution -{ - public IList KidsWithCandies(int[] candies, int extraCandy) - { - int maxCandy = candies.Max(); - return candies.Select(candy => candy + extraCandy >= maxCandy).ToList(); - } -} -``` - -## Ruby - -```ruby -def kids_with_candies(candies, extra_candy) - max_candy = candies.max - candies.map { |candy| candy + extra_candy >= max_candy } -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[1431. 拥有最多糖果的孩子 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1431-kids-with-the-greatest-number-of-candies). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1001-2000/1514-path-with-maximum-probability.md b/zh/1001-2000/1514-path-with-maximum-probability.md deleted file mode 100644 index 19ee671..0000000 --- a/zh/1001-2000/1514-path-with-maximum-probability.md +++ /dev/null @@ -1,231 +0,0 @@ -# 1514. Path with Maximum Probability - Best Practices of LeetCode Solutions -LeetCode link: [1514. Path with Maximum Probability](https://leetcode.com/problems/path-with-maximum-probability), difficulty: **Medium**. - -## LeetCode description of "1514. Path with Maximum Probability" -You are given an undirected weighted graph of `n` nodes (0-indexed), represented by an edge list where `edges[i] = [a, b]` is an undirected edge connecting the nodes `a` and `b` with a probability of success of traversing that edge `succProb[i]`. - -Given two nodes `start` and `end`, find the path with the maximum probability of success to go from `start` to `end` and return its success probability. - -If there is no path from `start` to `end`, return 0. Your answer will be accepted if it differs from the correct answer by at most **1e-5**. - -### [Example 1] -![](../../images/examples/1514_1.png) - -**Input**: `n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2` - -**Output**: `0.25000` - -**Explanation**: `There are two paths from start to end, one having a probability of success = 0.2 and the other has 0.5 * 0.5 = 0.25.` - -### [Example 2] -![](../../images/examples/1514_2.png) - -**Input**: `n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2` - -**Output**: `0.30000` - -### [Example 3] -![](../../images/examples/1514_3.png) - -**Input**: `n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2` - -**Output**: `0.00000` - -**Explanation**: `There is no path between 0 and 2.` - -### [Constraints] -- `2 <= n <= 10^4` -- `0 <= start, end < n` -- `start != end` -- `0 <= a, b < n` -- `a != b` -- `0 <= succProb.length == edges.length <= 2*10^4` -- `0 <= succProb[i] <= 1` -- There is at most one edge between every two nodes. - -### [Hints] -
- Hint 1 - Multiplying probabilities will result in precision errors. -
- -
- Hint 2 - Take log probabilities to sum up numbers instead of multiplying them. -
- -
- Hint 3 - Use Dijkstra's algorithm to find the minimum path between the two nodes after negating all costs. -
- -## Intuition -We can use **Dijkstra's algorithm**. - -![](../../images/graph_Dijkstra_algorithm_animation.gif) - -This animation is about **Dijkstra's algorithm** to find the shortest path between `a` and `b`. -It picks the unvisited vertex with the lowest distance, calculates the distance through it to each unvisited neighbor, and updates the neighbor's distance if smaller. Mark **visited** (set to red) when done with neighbors. - -In short, **Dijkstra's algorithm** means **to find the nearest point and walk through it, and never go back. Repeatedly**. - -## Complexity -**V**: vertex count, **E**: Edge count. - -### Dijkstra's algorithm without using `heap sort` -* Time: `O(V * V)`. -* Space: `O(V + E)`. - -### Dijkstra's algorithm using `heap sort` -* Time: `O(E * log(E))`. -* Space: `O(V + E)`. - -## Python -### Dijkstra's algorithm without using `heap sort` -The code will time out when executed on LeetCode, but this is not a problem with the code itself. The `heap sort` implementation below will not time out. -```python -class Solution: - def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float: - node_to_pairs = defaultdict(set) - - for i, (source_node, target_node) in enumerate(edges): - node_to_pairs[source_node].add((target_node, succ_prob[i])) - node_to_pairs[target_node].add((source_node, succ_prob[i])) - - max_probabilities = [0] * n - max_probabilities[start_node] = 1 - visited = [False] * n - - for _ in range(n - 1): - current_node = None - maximum_probability = 0 - - for node, probability in enumerate(max_probabilities): - if not visited[node] and probability > maximum_probability: - maximum_probability = probability - current_node = node - - if current_node is None: - break - - visited[current_node] = True - - for target_node, probability in node_to_pairs[current_node]: - probability_ = probability * max_probabilities[current_node] - - if probability_ > max_probabilities[target_node]: - max_probabilities[target_node] = probability_ - - return max_probabilities[end_node] -``` - -### Dijkstra's algorithm using `heap sort` -#### 1. `heap sort` without using `visited` -```python -import heapq - -class Solution: - def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float: - node_to_pairs = defaultdict(set) - - for i, (source_node, target_node) in enumerate(edges): - node_to_pairs[source_node].add((target_node, succ_prob[i])) - node_to_pairs[target_node].add((source_node, succ_prob[i])) - - max_probabilities = [0 for node in range(n)] - max_probabilities[start_node] = 1 - priority_queue = [(-1, start_node)] - - while priority_queue: - current_probability, current_node = heapq.heappop(priority_queue) - - if current_node == end_node: - return -current_probability - - for target_node, probability in node_to_pairs[current_node]: - probability_ = abs(current_probability) * probability - - if probability_ > max_probabilities[target_node]: - max_probabilities[target_node] = probability_ - # It may cause the same `target_node` added into `priority_queue` more than once, but it doesn't matter. Because only the one `heappush`ed first may change the `max_probabilities` data. - heapq.heappush(priority_queue, (-probability_, target_node)) - - return 0 -``` - -#### 2. `heap sort` using `visited` -```python -import heapq - -class Solution: - def maxProbability(self, n: int, edges: List[List[int]], succ_prob: List[float], start_node: int, end_node: int) -> float: - node_to_pairs = defaultdict(set) - - for i, (source_node, target_node) in enumerate(edges): - node_to_pairs[source_node].add((target_node, succ_prob[i])) - node_to_pairs[target_node].add((source_node, succ_prob[i])) - - max_probabilities = [0 for node in range(n)] - max_probabilities[start_node] = 1 - priority_queue = [(-1, start_node)] - visited = [False] * n # added 1 - - while priority_queue: - current_probability, current_node = heapq.heappop(priority_queue) - - if current_node == end_node: - return -current_probability - - if visited[current_node]: # added 3 - continue - - visited[current_node] = True # added 2 - - for target_node, probability in node_to_pairs[current_node]: - if visited[target_node]: # added 4 - continue - - probability_ = abs(current_probability) * probability - - if probability_ > max_probabilities[target_node]: - max_probabilities[target_node] = probability_ - # It may cause the same `target_node` added into `priority_queue` more than once, but it doesn't matter. Because only the one `heappush`ed first may change the `max_probabilities` data. - heapq.heappush(priority_queue, (-probability_, target_node)) - - return 0 -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C, Kotlin, Swift, Rust or other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1584-min-cost-to-connect-all-points-2.md b/zh/1001-2000/1584-min-cost-to-connect-all-points-2.md deleted file mode 100644 index 36f92f2..0000000 --- a/zh/1001-2000/1584-min-cost-to-connect-all-points-2.md +++ /dev/null @@ -1,188 +0,0 @@ -# 1584. Min Cost to Connect All Points - Best Practices of LeetCode Solutions (Kruskal's Algorithm) -LeetCode link: [1584. Min Cost to Connect All Points](https://leetcode.com/problems/min-cost-to-connect-all-points) - -## LeetCode problem description -You are given an array `points` representing integer coordinates of some points on a 2D-plane, where `points[i] = [xi, yi]`. - -The cost of connecting two points `[xi, yi]` and `[xj, yj]` is the manhattan distance between them: `|xi - xj| + |yi - yj|`, where `|val|` denotes the absolute value of `val`. - -Return _the minimum cost to make all points connected_. All points are connected if there is **exactly one** simple path between any two points. - -### Example 1 -![](../../images/examples/1584_1_1.png) -```java -Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]] -Output: 20 -Explanation: -``` -![](../../images/examples/1584_1_2.png) -``` -We can connect the points as shown above to get the minimum cost of 20. -Notice that there is a unique path between every pair of points. -``` - -### Example 2 -```java -Input: points = [[3,12],[-2,5],[-4,1]] -Output: 18 -``` - -### Constraints -- `1 <= points.length <= 1000` -- `-1000000 <= xi, yi <= 1000000` -- All pairs `(xi, yi)` are distinct. - -
- Hint 1 - Connect each pair of points with a weighted edge, the weight being the manhattan distance between those points. -
- -
- Hint 2 - The problem is now the cost of minimum spanning tree in graph with above edges. -
- -## Intuition -* Connect each pair of points with a **weighted** edge, the weight being the manhattan distance between those points. -* Cycles will increase the `cost`, so there is no cycle. -* A connected graph without cycles is called a tree. -* The problem is now the cost of **minimum spanning tree** in graph with above edges. -* A minimum spanning tree (MST) or minimum weight spanning tree is a subset of the edges of a connected, edge-weighted undirected graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight. - -### Another solution: Prim's Algorithm -Please see [1584. Min Cost to Connect All Points (Prim's Algorithm)](1584-min-cost-to-connect-all-points.md). - -This page, I will only talk about the solution of **Kruskal's Algorithm**. - -### Approach: Kruskal's Algorithm -- _Prim's Algorithm_ adds the closest point to the tree each time, while _Kruskal's Algorithm_ adds the shortest edge to the tree each time. -- If both vertices of an edge are already in the tree, this edge can be skipped. Because once this edge is added, a cycle will be formed, which will increase the cost and destroy the structure of the tree. -- To determine whether a cycle will be formed, the **Union-Find** algorithm can be used. -- Traverse all edges once, add up the lengths of the edges and return the sum as the result. -- If you are familiar with the **Union-Find** algorithm, it is easy to solve the problem with _Kruskal's algorithm_. However, this problem does not directly give the `edges` information, and we need to calculate it through the vertex information, which is not difficult, but this causes the algorithm to run slower than _Prim's Algorithm_ because there are too many edges. The more edges, the slower _Kruskal's Algorithm_. - -#### Compare to Prim's Algorithm -For this problem, `points` are given, so using `Prim's Algorithm` would be faster and easier to understand. - -Because if we use `Kruskal's Algorithm`, we have to convert `points` into `edges`, and we will get a fully dense graph. - -For sparse graphs, `Kruskal's Algorithm` is more efficient than `Prim's Algorithm`. - -## Complexity -- `V` is the `points.length`. -- `E` is the `edges.length`. In this problem, the `E` is `V * V`. - -* Time: `O(E * log(E))`. -* Space: `O(V * V)`. - -## Python -The following code can also be implemented by using `heap sort`, but it would be slower. -```python -from collections import deque - -class Solution: - def __init__(self): - self.parents = [] - - def minCostConnectPoints(self, points: List[List[int]]) -> int: - self.parents = list(range(len(points))) - result = 0 - edges = [] - - for i, point in enumerate(points): - for j in range(i + 1, len(points)): - distance = abs(point[0] - points[j][0]) + \ - abs(point[1] - points[j][1]) - edges.append((distance, i, j)) - - edges.sort() - edges = deque(edges) - - while edges: - distance, i, j = edges.popleft() - - if self.is_same_root(i, j): - continue - - self.unite(i, j) - - result += distance - - return result - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) - - self.parents[x] = root - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Python -```python -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1584-min-cost-to-connect-all-points.md b/zh/1001-2000/1584-min-cost-to-connect-all-points.md deleted file mode 100644 index b210651..0000000 --- a/zh/1001-2000/1584-min-cost-to-connect-all-points.md +++ /dev/null @@ -1,660 +0,0 @@ -# 1584. Min Cost to Connect All Points - Best Practices of LeetCode Solutions (Prim's Algorithm) -LeetCode link: [1584. Min Cost to Connect All Points](https://leetcode.com/problems/min-cost-to-connect-all-points) - -## LeetCode problem description -You are given an array `points` representing integer coordinates of some points on a 2D-plane, where `points[i] = [xi, yi]`. - -The cost of connecting two points `[xi, yi]` and `[xj, yj]` is the manhattan distance between them: `|xi - xj| + |yi - yj|`, where `|val|` denotes the absolute value of `val`. - -Return _the minimum cost to make all points connected_. All points are connected if there is **exactly one** simple path between any two points. - -### Example 1 -![](../../images/examples/1584_1_1.png) -```java -Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]] -Output: 20 -Explanation: -``` -![](../../images/examples/1584_1_2.png) -``` -We can connect the points as shown above to get the minimum cost of 20. -Notice that there is a unique path between every pair of points. -``` - -### Example 2 -```java -Input: points = [[3,12],[-2,5],[-4,1]] -Output: 18 -``` - -### Constraints -- `1 <= points.length <= 1000` -- `-1000000 <= xi, yi <= 1000000` -- All pairs `(xi, yi)` are distinct. - -
- Hint 1 - Connect each pair of points with a weighted edge, the weight being the manhattan distance between those points. -
- -
- Hint 2 - The problem is now the cost of minimum spanning tree in graph with above edges. -
- -## Intuition -* Connect each pair of points with a **weighted** edge, the weight being the manhattan distance between those points. -* Cycles will increase the `cost`, so there is no cycle. -* A connected graph without cycles is called a tree. -* The problem is now the cost of **minimum spanning tree** in graph with above edges. -* A minimum spanning tree (MST) or minimum weight spanning tree is a subset of the edges of a connected, edge-weighted undirected graph that connects all the vertices together, without any cycles and with the minimum possible total edge weight. -* One of the solutions for `MST` is the **Prim algorithm**, which is a _greedy algorithm_ and also a _dynamic programming algorithm_. - -### Another solution: Kruskal's Algorithm -Please see [1584. Min Cost to Connect All Points (Kruskal's Algorithm)](1584-min-cost-to-connect-all-points-2.md). - -This page, I will only talk about the solution of **Prim's Algorithm**. - -### Prim's Algorithm -- Initially, add any point to an empty graph, for example, the point with index 0. -- Next, add the second point. This second point is the **closest** point to the first point. -- An `min_distances` (or call it `dp`) array is needed to store the distances of other points to the first point. -- After the second point is added, add the third point in the same way. The third point is the **closest** point to the first two points. This time, only the distances of other points to the second point need to be calculated, because their distances to the first point have already been calculated and stored in the `min_distances` array. -- Update the `min_distances` array, and the array is a rolling array. -- Finally, all points are added to the graph. - -## Approach -Let us use the _common 5 steps_ to solve a _dynamic programming problem_. - -### Common five steps in dynamic programming -1. Determine the **meaning** of the `min_distances[i]` - * `min_distances[i]` represents the **minimum** `cost` (or call it `weight`, `distance`) of adding `points[i]` into current tree. - * `min_distances[i]` is an integer. -2. Determine the `min_distances` array's initial value - * Use the example 1 `points = [[0,0],[2,2],[3,10],[5,2],[7,0]]`: - ```python - After initialization, the 'min_distances' array would be: - # 0 1 2 3 4 # index - # 0 i i i i # `i` repreents a very large number - ``` -3. Determine the `min_distances` array's recurrence formula - * Try to complete the grid. In the process, you will get inspiration to derive the formula. - ```python - points = [[0,0],[2,2],[3,10],[5,2],[7,0]] - # 0 1 2 3 4 # index - # v 4 13 7 7 # min_distances. current_index will become 1 later becaue 4 is the closet. `v` reprents this point is 'visited', and its value is fixed. - # v v 9 3 7 # min_distances. current_index will become 3 later becaue 3 is the closet - # v v 9 v 4 # min_distances. current_index will become 4 later becaue 4 is the closet - # v v 9 v v # min_distances. current_index will become 2 later becaue it is the last one - # 0 4 9 3 4 # min_distances: 0 + 4 + 9 + 3 + 4 = 20 - ``` - * We can derive the `Recurrence Formula`: - ```python - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + - abs(points[i][1] - points[current_index][1]) - ) - ``` -4. Determine the `min_distances` array's traversal order - * The traversal order doesn't matter. -5. Check the `min_distances` array's value - * Print the `min_distances` to see if it is as expected. - -### Solution 1: Not use 'heap sort' -#### The process of coding -* Initialize `min_distances` and do the first iteration. -```python -min_distances = [float('inf')] * len(points) # This is just the `dp` array -min_distances[0] = 0 - -for i, _ in enumerate(points): - if i == 0: - continue - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[0][0]) + \ - abs(points[i][1] - points[0][1]) - ) -``` - -* Use `current_index` to replace the fixed index `0`: -```python -min_distances = [float('inf')] * len(points) # This is just the `dp` array -min_distances[0] = 0 -current_index = 0 - -for i, _ in enumerate(points): - if i == current_index: - continue - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + \ - abs(points[i][1] - points[current_index][1]) - ) -``` - -* Find the `next_index` of the point which is the **closest** to the existing tree. -```python - class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - min_distances = [float('inf')] * len(points) # This is just the `dp` array - min_distances[0] = 0 - current_index = 0 - next_index = None - min_distance = float('inf') - - for i, _ in enumerate(points): - if i == current_index: - continue - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + \ - abs(points[i][1] - points[current_index][1]) - ) - - if min_distances[i] < min_distance: - min_distance = min_distances[i] - next_index = i - - current_index = next_index -``` - -* Use a loop to add each point. To do so, there are two ways. - -Way 1: Use `pending_indexes` set and only process the indexes in it. -```python -current_index = 0 -pending_indexes = set(range(len(points))) - -while pending_indexes: - pending_indexes.remove(current_index) - - # ... -``` - -Way 2: We need an array named `visited` to record the indexes of the points already added. In the iteration, if a point has been added, just skip it. -```python -current_index = 0 -visited = [False] * len(points) -visited[current_index] = True - -for i, point in enumerate(points): - if visited[i]: - continue - - # ... -``` - -Which way do you prefer? I prefer `way 1` because it's easier to understand. - -* Return `sum(min_distances)`. - -### Solution 2: Use 'heap sort' -* If you use **heap sort**, `current_index`, `next_index`, `minimum_distance` is not needed, because _heap sort_ knows which is the minimum value. -* `visited` is also not needed, because each `heappop()` means that a point has been `visited`. - -## Complexity -`V` is the `points.length`. - -* Time: `O(V * V)`. All those solutions' time complexity are `O(n * n)`, because `heapq.heapify()` is `O(n)`. -* Space: `O(V)`. - -## Python -### Solution 1: Not use 'heap sort' -#### Way 1: Use `pending_indexes` set -```python -class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - min_distances = [float('inf') for _ in points] - min_distances[0] = 0 - current_index = 0 - pending_indexes = set(range(len(points))) - - while pending_indexes: - pending_indexes.remove(current_index) - next_index = None - minimum_distance = float('inf') - - for i in pending_indexes: - distance = get_distance(points[i], points[current_index]) - - if distance < min_distances[i]: - min_distances[i] = distance - - if min_distances[i] < minimum_distance: - minimum_distance = min_distances[i] - next_index = i - - current_index = next_index - - return sum(min_distances) - - -def get_distance(point1, point2): - return abs(point2[0] - point1[0]) + abs(point2[1] - point1[1]) -``` - -#### Way 2: Use `visited` array -```python -class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - min_distances = [float('inf')] * len(points) # This is just the `dp` array - min_distances[0] = 0 - - current_index = 0 - visited = [False] * len(points) - - while current_index is not None: - visited[current_index] = True - next_index = None - minimum_distance = float('inf') - - for i, point in enumerate(points): - if visited[i]: - continue - - distance = \ - abs(point[0] - points[current_index][0]) + \ - abs(point[1] - points[current_index][1]) - - if distance < min_distances[i]: - min_distances[i] = distance - - if min_distances[i] < minimum_distance: - minimum_distance = min_distances[i] - next_index = i - - current_index = next_index - - return sum(min_distances) -``` - -### Solution 2: Use 'heap sort' -```python -class Solution: - def minCostConnectPoints(self, points: List[List[int]]) -> int: - result = 0 - min_distances = [[float('inf'), i] for i in range(len(points))] - min_distances[0][0] = 0 - - while min_distances: - distance_, current_index = heapq.heappop(min_distances) - result += distance_ - - for min_distance in min_distances: - point = points[min_distance[1]] - distance = get_distance(point, points[current_index]) - - if distance < min_distance[0]: - min_distance[0] = distance - - heapq.heapify(min_distances) - - return result - - -def get_distance(point1, point2): - return abs(point2[0] - point1[0]) + abs(point2[1] - point1[1]) -``` - -## Java -### Solution 1: Not use 'heap sort' -#### Way 1: Use `pending_indexes` set -```java -class Solution { - public int minCostConnectPoints(int[][] points) { - var minDistances = new int[points.length]; // This is just the `dp` array - Arrays.fill(minDistances, Integer.MAX_VALUE); - minDistances[0] = 0; - - var currentIndex = 0; - var pendingIndexes = new HashSet(); - for (var i = 0; i < points.length; i++) { - pendingIndexes.add(i); - } - - while (!pendingIndexes.isEmpty()) { - pendingIndexes.remove(currentIndex); - - var nextIndex = -1; - var minimumDistance = Integer.MAX_VALUE; - - for (var i : pendingIndexes) { - var distance = - Math.abs(points[i][0] - points[currentIndex][0]) + - Math.abs(points[i][1] - points[currentIndex][1]); - - if (distance < minDistances[i]) { - minDistances[i] = distance; - } - - if (minDistances[i] < minimumDistance) { - minimumDistance = minDistances[i]; - nextIndex = i; - } - } - - currentIndex = nextIndex; - } - - return IntStream.of(minDistances).sum(); - } -} -``` - -#### Way 2: Use `visited` array -```java -class Solution { - public int minCostConnectPoints(int[][] points) { - var minDistances = new int[points.length]; // This is just the `dp` array - Arrays.fill(minDistances, Integer.MAX_VALUE); - minDistances[0] = 0; - - var currentIndex = 0; - var visited = new boolean[points.length]; - - while (currentIndex != -1) { - visited[currentIndex] = true; - var nextIndex = -1; - var minDistance = Integer.MAX_VALUE; - - for (var i = 0; i < points.length; i++) { - if (visited[i]) { - continue; - } - - minDistances[i] = Math.min( - minDistances[i], - Math.abs(points[i][0] - points[currentIndex][0]) + - Math.abs(points[i][1] - points[currentIndex][1]) - ); - - if (minDistances[i] < minDistance) { - minDistance = minDistances[i]; - nextIndex = i; - } - } - - currentIndex = nextIndex; - } - - return IntStream.of(minDistances).sum(); - } -} -``` - -### Solution 2: Use 'heap sort' -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```cpp -class Solution { -public: - int minCostConnectPoints(vector>& points) { - auto min_distances = vector(points.size(), INT_MAX); // This is just the `dp` array - min_distances[0] = 0; - - auto current_index = 0; - auto visited = vector(points.size()); - - while (current_index != -1) { - visited[current_index] = true; - auto next_index = -1; - auto min_distance = INT_MAX; - - for (auto i = 0; i < points.size(); i++) { - if (visited[i]) { - continue; - } - - min_distances[i] = min( - min_distances[i], - abs(points[i][0] - points[current_index][0]) + - abs(points[i][1] - points[current_index][1]) - ); - - if (min_distances[i] < min_distance) { - min_distance = min_distances[i]; - next_index = i; - } - } - - current_index = next_index; - } - - return reduce(min_distances.begin(), min_distances.end()); - } -}; -``` - -### Solution 2: Use 'heap sort' -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```javascript -var minCostConnectPoints = function (points) { - const minDistances = Array(points.length).fill(Number.MAX_SAFE_INTEGER) // This is just the `dp` array - minDistances[0] = 0 - - let currentIndex = 0 - const visited = Array(points.length).fill(false) - - while (currentIndex != -1) { - visited[currentIndex] = true - let nextIndex = -1 - let minDistance = Number.MAX_SAFE_INTEGER - - for (let i = 0; i < points.length; i++) { - if (visited[i]) { - continue - } - - minDistances[i] = Math.min( - minDistances[i], - Math.abs(points[i][0] - points[currentIndex][0]) + - Math.abs(points[i][1] - points[currentIndex][1]) - ) - - if (minDistances[i] < minDistance) { - minDistance = minDistances[i] - nextIndex = i - } - } - - currentIndex = nextIndex - } - - return _.sum(minDistances) -}; -``` - -### Solution 2: Use 'heap sort' -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```c# -public class Solution -{ - public int MinCostConnectPoints(int[][] points) - { - var minDistances = new int[points.Length]; // This is just the `dp` array - Array.Fill(minDistances, Int32.MaxValue); - minDistances[0] = 0; - - int currentIndex = 0; - var visited = new bool[points.Length]; - - while (currentIndex != -1) - { - visited[currentIndex] = true; - int nextIndex = -1; - int minDistance = Int32.MaxValue; - - for (int i = 0; i < points.Length; i++) - { - if (visited[i]) - { - continue; - } - - minDistances[i] = Math.Min( - minDistances[i], - Math.Abs(points[i][0] - points[currentIndex][0]) + - Math.Abs(points[i][1] - points[currentIndex][1]) - ); - - if (minDistances[i] < minDistance) - { - minDistance = minDistances[i]; - nextIndex = i; - } - } - - currentIndex = nextIndex; - } - - return minDistances.Sum(); - } -} -``` - -### Solution 2: Use 'heap sort' -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```go -func minCostConnectPoints(points [][]int) int { - minDistances := slices.Repeat([]int{math.MaxInt32}, len(points)) // This is just the `dp` array - minDistances[0] = 0 - - currentIndex := 0 - visited := make([]bool, len(points)) - - for currentIndex != -1 { - visited[currentIndex] = true - nextIndex := -1 - minDistance := math.MaxInt32 - - for i, point := range points { - if visited[i] { - continue - } - - minDistances[i] = min( - minDistances[i], - int( - math.Abs(float64(point[0] - points[currentIndex][0])) + - math.Abs(float64(point[1] - points[currentIndex][1])), - ), - ) - - if minDistances[i] < minDistance { - minDistance = minDistances[i] - nextIndex = i - } - } - - currentIndex = nextIndex - } - - distanceSum := 0 - for _, distance := range minDistances { - distanceSum += distance - } - - return distanceSum -} -``` - -### Solution 2: Use 'heap sort' -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -### Solution 1: Not use 'heap sort' -#### Way 2: Use `visited` array -```ruby -def min_cost_connect_points(points) - min_distances = Array.new(points.size, Float::INFINITY) # This is just the `dp` array. - min_distances[0] = 0 - - current_index = 0 - visited = Array.new(points.size, false) - - while !current_index.nil? - visited[current_index] = true - next_index = nil - min_distance = Float::INFINITY - - points.each_with_index do |point, i| - next if visited[i] - - min_distances[i] = [ - min_distances[i], - (point[0] - points[current_index][0]).abs + - (point[1] - points[current_index][1]).abs - ].min - - if min_distances[i] < min_distance - min_distance = min_distances[i] - next_index = i - end - end - - current_index = next_index - end - - min_distances.sum -end -``` - -### Solution 2: Use 'heap sort' -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1768-merge-strings-alternately.md b/zh/1001-2000/1768-merge-strings-alternately.md deleted file mode 100644 index 3a03ebb..0000000 --- a/zh/1001-2000/1768-merge-strings-alternately.md +++ /dev/null @@ -1,244 +0,0 @@ -# 1768. 交替合并字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[1768. 交替合并字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1768-merge-strings-alternately),体验更佳! - -力扣链接:[1768. 交替合并字符串](https://leetcode.cn/problems/merge-strings-alternately), 难度等级:**简单**。 - -## LeetCode “1768. 交替合并字符串”问题描述 - -给你两个字符串 `word1` 和 `word2` 。请你从 `word1` 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 - -返回 **合并后的字符串** 。 - -### [示例 1] - -**输入**: `word1 = "abc", word2 = "pqr"` - -**输出**: `"apbqcr"` - -**解释**: - -
The merged string will be merged as so:
-word1:  a   b   c
-word2:    p   q   r
-merged: a p b q c r
-
- -### [示例 2] - -**输入**: `word1 = "ab", word2 = "pqrs"` - -**输出**: `"apbqrs"` - -**解释**: - -
Notice that as word2 is longer, "rs" is appended to the end.
-word1:  a   b 
-word2:    p   q   r   s
-merged: a p b q   r   s
-
- -### [示例 3] - -**输入**: `word1 = "abcd", word2 = "pq"` - -**输出**: `"apbqcd"` - -**解释**: - -
Notice that as word1 is longer, "cd" is appended to the end.
-word1:  a   b   c   d
-word2:    p   q 
-merged: a p b q c   d
-
- -### [约束] - -- `1 <= word1.length, word2.length <= 100` -- `word1` 和 `word2` 由小写英文字母组成 - - -### [Hints] - -
- 提示 1 - Use two pointers, one pointer for each string. Alternately choose the character from each pointer, and move the pointer upwards. - - -
- -## 思路 - -这个问题要求我们合并两个字符串 `word1` 和 `word2`,方法是交替选取字符,从 `word1` 开始。如果一个字符串比另一个长,那么较长字符串中多余的字符应该追加到合并结果的末尾。 - -核心思路是同时遍历两个字符串,从 `word1` 中取一个字符,然后从 `word2` 中取一个字符,并将它们添加到我们的结果中。只要两个字符串中都还有可用的字符,这个过程就会继续。 - -一旦较短字符串的字符用完,我们就简单地从较长字符串中取出所有剩余的字符,并将它们追加到我们的结果中。 - -## 步骤 - -1. 初始化一个空字符串(或字符列表、字符串构建器)来存储合并后的结果。 -2. 确定 `word1` 和 `word2` 的长度。设它们分别为 `n1` 和 `n2`。 -3. 找出这两个长度中的较小值,称其为 `min_len = min(n1, n2)`。这个 `min_len` 是我们可以从两个字符串中交替选取的字符数。 -4. 从 `i = 0` 迭代到 `min_len - 1`: - * 将 `word1` 的第 `i` 个字符追加到结果中。 - * 将 `word2` 的第 `i` 个字符追加到结果中。 -5. 循环结束后,我们已经处理了两个字符串中的 `min_len` 个字符。 -6. 确定哪个字符串可能有多余的字符。设其为 `longer_word`。 - * 如果 `word1` 的长度 (`n1`) 大于 `min_len`,则 `longer_word` 是 `word1`。 - * 否则,`longer_word` 是 `word2`。 -7. 将 `longer_word` 的剩余部分(即从索引 `min_len` 开始的 `longer_word`)追加到 `result` 中。8. 返回最终合并的字符串。 - -## 复杂度 - -- 时间复杂度: `O(N)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def mergeAlternately(self, word1: str, word2: str) -> str: - min_size = min(len(word1), len(word2)) - result = "" - - for i in range(min_size): - result += f'{word1[i]}{word2[i]}' - - longer_word = word1 if len(word1) > min_size else word2 - - return result + longer_word[min_size:] -``` - -## Java - -```java -class Solution { - public String mergeAlternately(String word1, String word2) { - int minSize = Math.min(word1.length(), word2.length()); - StringBuilder result = new StringBuilder(); - - for (int i = 0; i < minSize; i++) { - result.append(word1.charAt(i)).append(word2.charAt(i)); - } - - String longerWord = (word1.length() > word2.length()) ? word1 : word2; - result.append(longerWord.substring(minSize)); - - return result.toString(); - } -} -``` - -## C++ - -```cpp -class Solution { -public: - string mergeAlternately(string word1, string word2) { - int min_size = min(word1.length(), word2.length()); - string result; - - for (int i = 0; i < min_size; ++i) { - result += word1[i]; - result += word2[i]; - } - - auto& longer_word = (word1.length() > min_size) ? word1 : word2; - result += longer_word.substr(min_size); - - return result; - } -}; -``` - -## JavaScript - -```javascript -var mergeAlternately = function(word1, word2) { - const minSize = Math.min(word1.length, word2.length); - let result = ""; - - for (let i = 0; i < minSize; i++) { - result += word1[i] + word2[i]; - } - - const longerWord = word1.length > word2.length ? word1 : word2; - result += longerWord.slice(minSize); - - return result; -}; -``` - -## Go - -```go -func mergeAlternately(word1, word2 string) string { - minSize := int(math.Min(float64(len(word1)), float64(len(word2)))) - var result strings.Builder - - for i := 0; i < minSize; i++ { - result.WriteByte(word1[i]) - result.WriteByte(word2[i]) - } - - longerWord := word1 - if len(word2) > len(word1) { - longerWord = word2 - } - result.WriteString(longerWord[minSize:]) - - return result.String() -} -``` - -## C# - -```csharp -public class Solution -{ - public string MergeAlternately(string word1, string word2) - { - int minSize = Math.Min(word1.Length, word2.Length); - var result = new StringBuilder(); - - for (int i = 0; i < minSize; i++) - result.Append(word1[i]).Append(word2[i]); - - string longerWord = word1.Length > word2.Length ? word1 : word2; - result.Append(longerWord.Substring(minSize)); - - return result.ToString(); - } -} -``` - -## Ruby - -```ruby -def merge_alternately(word1, word2) - min_size = [ word1.size, word2.size ].min - result = "" - - min_size.times { |i| result << word1[i] << word2[i] } - - longer_word = word1.size > word2.size ? word1 : word2 - result << longer_word[min_size..] - - result -end -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[1768. 交替合并字符串 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/1768-merge-strings-alternately). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/1001-2000/1971-find-if-path-exists-in-graph-2.md b/zh/1001-2000/1971-find-if-path-exists-in-graph-2.md deleted file mode 100644 index b13f02c..0000000 --- a/zh/1001-2000/1971-find-if-path-exists-in-graph-2.md +++ /dev/null @@ -1,435 +0,0 @@ -# LeetCode 1971. Find if Path Exists in Graph's Solution: UnionFind -LeetCode link: [1971. Find if Path Exists in Graph](https://leetcode.com/problems/find-if-path-exists-in-graph) - -## LeetCode problem description -There is a **bi-directional** graph with `n` vertices, where each vertex is labeled from `0` to `n - 1` (**inclusive**). The edges in the graph are represented as a 2D integer array `edges`, where each `edges[i] = [ui, vi]` denotes a bi-directional edge between vertex `ui` and vertex `vi`. Every vertex pair is connected by **at most one** edge, and no vertex has an edge to itself. - -You want to determine if there is a **valid path** that exists from vertex `source` to vertex `destination`. - -Given `edges` and the integers `n`, `source`, and `destination`, return `true` _if there is a **valid path** from `source` to `destination`, or `false` otherwise_. - -### Example 1 -![](../../images/examples/1971_1.png) -``` -Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2 -Output: true -Explanation: There are two paths from vertex 0 to vertex 2: -- 0 → 1 → 2 -- 0 → 2 -``` - -### Example 2 -![](../../images/examples/1971_2.png) -``` -Input: n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5 -Output: false -Explanation: There is no path from vertex 0 to vertex 5. -``` - -### Constraints -- `1 <= n <= 2 * 10^5` -- `0 <= edges.length <= 2 * 10^5` -- `edges[i].length == 2` -- `0 <= ui, vi <= n - 1` -- `ui != vi` -- `0 <= source, destination <= n - 1` -- There are no duplicate edges. -- There are no self edges. - -## Another solution: Breadth-First Search Algorithm -Please see [1971. Find if Path Exists in Graph ('Breadth-First Search' Solution)](1971-find-if-path-exists-in-graph.md). - -## Intuition -This graph may have multiple **connected components**. - -![](../../images/graph_undirected_2.png) - -- Initially, we start from `source` vertex which belongs to one of the `connected components`. -- We need to find if there is a path from `source` to `destination`. This question is equivalent to determine if `source` and `destination` vertices belong to the same `connected component`. -- A `tree` is a type of `graph`. If two nodes are in the same tree, then return `true`. So we need a method `in_same_tree(node1, node2)` to return a boolean value. -- We are given `edges` data and need to divide them into multiple groups, each group can be abstracted into a **tree**. -- `UnionFind` algorithm is designed for grouping and searching data. - -### 'UnionFind' algorithm -- `UnionFind` algorithm typically has three methods: - - The `unite(node1, node2)` operation can be used to merge two trees. - - The `find_root(node)` method can be used to return the root of a node. - - The `is_same_root(node1, node2)` method is used to determine whether two nodes are in the same tree. - -## Approach (UnionFind algorithm) -1. Initially, each node is in its own group. -1. Iterate `edges` data and `unite(node1, node2)`. -1. Return `is_same_root(source, destination)`. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Standard UnionFind algorithm (recommended) -```python -class Solution: - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - self.parents = list(range(n)) - - for x, y in edges: - self.unite(x, y) - - return self.is_same_root(source, destination) - - def unite(self, x, y): - root_x = self.find_root(x) - root_y = self.find_root(y) - - self.parents[root_y] = root_x # Error-prone point 1 - - def find_root(self, x): - parent = self.parents[x] - - if x == parent: - return x - - root = self.find_root(parent) # Error-prone point 2 - - self.parents[x] = root # Error-prone point 3 - - return root - - def is_same_root(self, x, y): - return self.find_root(x) == self.find_root(y) -``` - -### Another UnionFind algorithm (using a map and an array of set) -* This solution is slower than the `standard UnionFind algorithm`, but it is straightforward. -* The applicability of this solution is not as wide as the `standard UnionFind algorithm` because data in a set don't have association. - The `standard UnionFind algorithm` has a `parent` array with association of nodes. - -```python -class Solution: - def __init__(self): - self.disjoint_sets = [] - self.value_to_set_id = {} - - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - for i in range(n): - self.disjoint_sets.append({i}) - self.value_to_set_id[i] = i - - for x, y in edges: - self.unite(x, y) - - return self.in_same_set(source, destination) - - def unite(self, x, y): - if self.in_same_set(x, y): - return - - bigger = x - smaller = y - - if len(self.get_set(x)) < len(self.get_set(y)): - bigger = y - smaller = x - - for value in self.get_set(smaller): - self.get_set(bigger).add(value) - self.value_to_set_id[value] = self.value_to_set_id.get(bigger) - - def get_set(self, value): - set_id = self.value_to_set_id.get(value) - return self.disjoint_sets[set_id] - - def in_same_set(self, x, y): - return self.get_set(x) == self.get_set(y) -``` - -## Java -```java -class Solution { - private int[] parents; - - public boolean validPath(int n, int[][] edges, int source, int destination) { - parents = new int[n]; - - for (var i = 0; i < n; i++) { - parents[i] = i; - } - - for (var edge : edges) { - unite(edge[0], edge[1]); - } - - return isSameRoot(source, destination); - } - - private void unite(int x, int y) { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - private int findRoot(int x) { - var parent = parents[x]; - - if (x == parent) { - return x; - } - - var root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - private boolean isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -} -``` - -## C++ -```cpp -class Solution { -public: - bool validPath(int n, vector>& edges, int source, int destination) { - for (auto i = 0; i < n; i++) { - parents.push_back(i); - } - - for (auto& edge : edges) { - unite(edge[0], edge[1]); - } - - return isSameRoot(source, destination); - } - -private: - vector parents; - - void unite(int x, int y) { - int root_x = findRoot(x); - int root_y = findRoot(y); - - parents[root_y] = root_x; // Error-prone point 1 - } - - int findRoot(int x) { - auto parent = parents[x]; - - if (x == parent) { - return x; - } - - auto root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) { - return findRoot(x) == findRoot(y); - } -}; -``` - -## JavaScript -```javascript -let parents - -var validPath = function (n, edges, source, destination) { - parents = [] - for (let i = 0; i < n; i++) { - parents.push(i) - } - - for (const [a, b] of edges) { - unite(a, b) - } - - return isSameRoot(source, destination) -}; - -function unite(x, y) { - rootX = findRoot(x) - rootY = findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -function findRoot(x) { - const parent = parents[x] - - if (x == parent) { - return x - } - - const root = findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -function isSameRoot(x, y) { - return findRoot(x) == findRoot(y) -} -``` - -## C# -```c# -public class Solution -{ - int[] parents; - - public bool ValidPath(int n, int[][] edges, int source, int destination) - { - parents = new int[n]; - - for (int i = 0; i < n; i++) - parents[i] = i; - - foreach (int[] edge in edges) - { - unite(edge[0], edge[1]); - } - - return isSameRoot(source, destination); - } - - void unite(int x, int y) - { - int rootX = findRoot(x); - int rootY = findRoot(y); - - parents[rootY] = rootX; // Error-prone point 1 - } - - int findRoot(int x) - { - int parent = parents[x]; - - if (x == parent) - return x; - - int root = findRoot(parent); // Error-prone point 2 - - parents[x] = root; // Error-prone point 3 - - return root; - } - - bool isSameRoot(int x, int y) - { - return findRoot(x) == findRoot(y); - } -} -``` - -## Go -```go -var parents []int - -func validPath(n int, edges [][]int, source int, destination int) bool { - parents = make([]int, n) - for i := 0; i < n; i++ { - parents[i] = i - } - - for _, edge := range edges { - unite(edge[0], edge[1]) - } - - return isSameRoot(source, destination) -} - -func unite(x, y int) { - rootX := findRoot(x) - rootY := findRoot(y) - - parents[rootY] = rootX // Error-prone point 1 -} - -func findRoot(x int) int { - parent := parents[x]; - - if x == parent { - return x - } - - root := findRoot(parent) // Error-prone point 2 - - parents[x] = root // Error-prone point 3 - - return root -} - -func isSameRoot(x, y int) bool { - return findRoot(x) == findRoot(y) -} -``` - -## Ruby -```ruby -def valid_path(n, edges, source, destination) - @parents = (0...n).to_a - - edges.each do |edge| - unite(edge[0], edge[1]) - end - - is_same_root(source, destination) -end - -def unite(x, y) - root_x = find_root(x) - root_y = find_root(y) - - @parents[root_y] = root_x # Error-prone point 1 -end - -def find_root(x) - parent = @parents[x] - - if x == parent - return x - end - - root = find_root(parent) # Error-prone point 2 - - @parents[x] = root # Error-prone point 3 - - root -end - -def is_same_root(x, y) - find_root(x) == find_root(y) -end -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/1001-2000/1971-find-if-path-exists-in-graph.md b/zh/1001-2000/1971-find-if-path-exists-in-graph.md deleted file mode 100644 index 4679611..0000000 --- a/zh/1001-2000/1971-find-if-path-exists-in-graph.md +++ /dev/null @@ -1,188 +0,0 @@ -# LeetCode 1971. Find if Path Exists in Graph's Solution (Breadth-First Search) -LeetCode link: [1971. Find if Path Exists in Graph](https://leetcode.com/problems/find-if-path-exists-in-graph) - -## LeetCode problem description -There is a **bi-directional** graph with `n` vertices, where each vertex is labeled from `0` to `n - 1` (**inclusive**). The edges in the graph are represented as a 2D integer array `edges`, where each `edges[i] = [ui, vi]` denotes a bi-directional edge between vertex `ui` and vertex `vi`. Every vertex pair is connected by **at most one** edge, and no vertex has an edge to itself. - -You want to determine if there is a **valid path** that exists from vertex `source` to vertex `destination`. - -Given `edges` and the integers `n`, `source`, and `destination`, return `true` _if there is a **valid path** from `source` to `destination`, or `false` otherwise_. - -### Example 1 -![](../../images/examples/1971_1.png) -``` -Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2 -Output: true -Explanation: There are two paths from vertex 0 to vertex 2: -- 0 → 1 → 2 -- 0 → 2 -``` - -### Example 2 -![](../../images/examples/1971_2.png) -``` -Input: n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5 -Output: false -Explanation: There is no path from vertex 0 to vertex 5. -``` - -### Constraints -- `1 <= n <= 2 * 10^5` -- `0 <= edges.length <= 2 * 10^5` -- `edges[i].length == 2` -- `0 <= ui, vi <= n - 1` -- `ui != vi` -- `0 <= source, destination <= n - 1` -- There are no duplicate edges. -- There are no self edges. - -## Another solution: UnionFind Algorithm -Please see [1971. Find if Path Exists in Graph (UnionFind Solution)](1971-find-if-path-exists-in-graph-2.md). - -## Intuition -This graph may have multiple **connected components**. - -![](../../images/graph_undirected_2.png) - -Initially, we start from `source` vertex which belongs to one of the `connected components`. -We need to find if there is a path from `source` to `destination`. This question is equivalent to determine if `source` and `destination` vertices belong to the same `connected component`. - -### Breadth-First Search -* There are two major ways to explore a `connected component`: **Breadth-First Search** and **Depth-First Search**. -* For **Depth-First Search**, there are two ways to make it: `Recursive` and `Iterative`. Please see [200. Number of Islands (Depth-First Search)](../1-1000/200-number-of-islands.md). - -![](../../images/binary_tree_BFS_1.gif) - -* As shown in the figure above, **breadth-first search** can be thought of as visiting vertices in rounds and rounds. - -* `breadth-first search` emphasizes first-in-first-out, so a **queue** is needed. - -## Approach (Breadth-First Search) -1. Starting at the `source` vertex, find all the vertices of the `connected component` by `breadth-first search`. -1. In order to conduct `breadth-first search`, we need to know the adjacent vertices of a vertex. So we need a `map` `vertex_to_adjacent_vertices`. We can initialize the `map` by transforming `edges`. -1. We need to mark all vertices on the same connected component as vertex `source` as `visited` because visited vertices don't need to be visited again. -1. Once vertex `destination` is encountered, return `true`. - -## Complexity -* Time: `O(n)`. -* Space: `O(n)`. - -## Python -### Breadth-first search -```python -class Solution: - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - vertex_queue = deque([source]) - visited_vertices = set([source]) - - vertex_to_adjacent_vertices = defaultdict(list) - for vertex0, vertex1 in edges: - vertex_to_adjacent_vertices[vertex0].append(vertex1) - vertex_to_adjacent_vertices[vertex1].append(vertex0) - - while vertex_queue: - vertex = vertex_queue.popleft() - - if vertex == destination: - return True - - for adjacent_vertex in vertex_to_adjacent_vertices[vertex]: - if adjacent_vertex not in visited_vertices: - vertex_queue.append(adjacent_vertex) - visited_vertices.add(adjacent_vertex) # Mark visited as soon as `vertex_queue.append(adjacent_vertex)`. Otherwise it may have performance issue! - - return False -``` - -### Depth-first search -```python -class Solution: - def __init__(self): - self.visited = set() - self.found = False - - def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool: - if source == destination: - return True - - self.destination = destination - self.vertex_to_vertices = defaultdict(list) - - for vertex1, vertex2 in edges: - self.vertex_to_vertices[vertex1].append(vertex2) - self.vertex_to_vertices[vertex2].append(vertex1) - - self.depth_first_search(source) - - return self.found - - def depth_first_search(self, vertex_): - if self.found: - return - - for vertex in self.vertex_to_vertices[vertex_]: - if vertex == self.destination: - self.found = True - return - - if vertex in self.visited: - continue - - self.visited.add(vertex) - self.depth_first_search(vertex) -``` - -## Java -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C++ -```cpp -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## JavaScript -```javascript -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## C# -```c# -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Go -```go -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Ruby -```ruby -# Welcome to create a PR to complete the code of this language, thanks! -``` - -## C -```c -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Kotlin -```kotlin -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Swift -```swift -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Rust -```rust -// Welcome to create a PR to complete the code of this language, thanks! -``` - -## Other languages -``` -// Welcome to create a PR to complete the code of this language, thanks! -``` diff --git a/zh/2001-3000/.keep b/zh/2001-3000/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/zh/3001-4000/.keep b/zh/3001-4000/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/zh/3001-4000/3478-choose-k-elements-with-maximum-sum.md b/zh/3001-4000/3478-choose-k-elements-with-maximum-sum.md deleted file mode 100644 index e9a5c1e..0000000 --- a/zh/3001-4000/3478-choose-k-elements-with-maximum-sum.md +++ /dev/null @@ -1,140 +0,0 @@ -# 3478. 选出和最大的 K 个元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[3478. 选出和最大的 K 个元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/3478-choose-k-elements-with-maximum-sum),体验更佳! - -力扣链接:[3478. 选出和最大的 K 个元素](https://leetcode.cn/problems/choose-k-elements-with-maximum-sum), 难度等级:**中等**。 - -## LeetCode “3478. 选出和最大的 K 个元素”问题描述 - -给你两个整数数组,`nums1` 和 `nums2`,长度均为 `n`,以及一个正整数 `k` 。 - -对从 `0` 到 `n - 1` 每个下标 `i` ,执行下述操作: - -- 找出所有满足 `nums1[j]` 小于 `nums1[i]` 的下标 `j` 。 -- 从这些下标对应的 `nums2[j]` 中选出 至多 `k` 个,并 最大化 这些值的总和作为结果。 - -返回一个长度为 `n` 的数组 `answer` ,其中 `answer[i]` 表示对应下标 `i` 的结果。 - - -### [示例 1] - -**输入**: `nums1 = [4,2,1,5,3], nums2 = [10,20,30,40,50], k = 2` - -**输出**: `[80,30,0,80,50]` - -**解释**: - -
    -
  • 对于 i = 0 :满足 nums1[j] < nums1[0] 的下标为 [1, 2, 4] ,选出其中值最大的两个,结果为 50 + 30 = 80
  • -
  • 对于 i = 1 :满足 nums1[j] < nums1[1] 的下标为 [2] ,只能选择这个值,结果为 30
  • -
  • 对于 i = 2 :不存在满足 nums1[j] < nums1[2] 的下标,结果为 0
  • -
  • 对于 i = 3 :满足 nums1[j] < nums1[3] 的下标为 [0, 1, 2, 4] ,选出其中值最大的两个,结果为 50 + 30 = 80
  • -
  • 对于 i = 4 :满足 nums1[j] < nums1[4] 的下标为 [1, 2] ,选出其中值最大的两个,结果为 30 + 20 = 50
  • -
- - -### [示例 2] - -**输入**: `nums1 = [2,2,2,2], nums2 = [3,1,2,3], k = 1` - -**输出**: `[0,0,0,0]` - -**解释**: - -

由于 nums1 中的所有元素相等,不存在满足条件 nums1[j] < nums1[i],所有位置的结果都是 0

- - -### [约束] - -- `n == nums1.length == nums2.length` -- `1 <= n <= 10^5` -- `1 <= nums1[i], nums2[i] <= 10^6` -- `1 <= k <= n` - -### [Hints] - -
- 提示 1 - Sort `nums1` and its corresponding `nums2` values together based on `nums1`. - - -
- -
- 提示 2 - Use a max heap to track the top `k` values of `nums2` as you process each element in the sorted order. - - -
- -## 思路 - -- 要求1:找出所有满足 `nums1[j]` 小于 `nums1[i]` 的下标 `j` 。 - 看到这个,大家一定会想到把 `nums1` 按从小到大排序,这样,前面的小于等于后面的,但一排序下标就**乱**了。如果对这个问题没有好办法解决,整个题目就做不出来。先请思考下。 - -
点击查看答案

在排序时带上索引下标,即排序的对象是元组`(num, index)`的数组。这个技术**一定要掌握**,许多题目都会用到。

- - 解决了上面的问题,下标就都有了,我们再看: - -- 要求2:从这些下标对应的 `nums2[j]` 中选出 至多 `k` 个,并 **最大化** 这些值的总和作为结果。 - - 看到这个,你想到用什么好方法了吗? - -
点击查看答案

堆排序,维护一个大小为 `k` 的大根堆。这也是经常考察的知识点,**一定要掌握**哦。

- - 看到这,请你先按上文提示把代码实现一下。 - -- 最后,发现还要对连续出现的重复的 `num` 进行特别处理,即相同的 `num` 对应的 `answer` 中的值应该是一样的。处理方法有多种,怎么处理最简单呢? - -
点击查看答案

用一个 `Map`, `key`为 `num`, 相同的 `key` 直接使用 `key` 对应的`值`。

- -## 复杂度 - -- 时间复杂度: `O(N * logN)`. -- 空间复杂度: `O(N)`. - -## Python - -```python -class Solution: - def findMaxSum(self, nums1: List[int], nums2: List[int], k: int) -> List[int]: - num_index_list = [(num, index) for index, num in enumerate(nums1)] # key 1 - num_index_list.sort() - - answer = [None] * len(nums1) - k_max_nums = [] - sum_ = 0 - num_to_sum = defaultdict(int) # key 2 - - for i, num_index in enumerate(num_index_list): - num, index = num_index - - if num in num_to_sum: - answer[index] = num_to_sum[num] - else: - answer[index] = sum_ - num_to_sum[num] = sum_ - - heapq.heappush(k_max_nums, nums2[index]) - sum_ += nums2[index] - - if len(k_max_nums) > k: - num = heapq.heappop(k_max_nums) # key 3 - sum_ -= num - - return answer -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[3478. 选出和最大的 K 个元素 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/3478-choose-k-elements-with-maximum-sum). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/3001-4000/3494-find-the-minimum-amount-of-time-to-brew-potions.md b/zh/3001-4000/3494-find-the-minimum-amount-of-time-to-brew-potions.md deleted file mode 100644 index 01e3bb0..0000000 --- a/zh/3001-4000/3494-find-the-minimum-amount-of-time-to-brew-potions.md +++ /dev/null @@ -1,441 +0,0 @@ -# 3494. 酿造药水需要的最少总时间 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解 - -访问原文链接:[3494. 酿造药水需要的最少总时间 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/3494-find-the-minimum-amount-of-time-to-brew-potions),体验更佳! - -力扣链接:[3494. 酿造药水需要的最少总时间](https://leetcode.cn/problems/find-the-minimum-amount-of-time-to-brew-potions), 难度等级:**中等**。 - -## LeetCode “3494. 酿造药水需要的最少总时间”问题描述 - -给你两个长度分别为 `n` 和 `m` 的整数数组 `skill` 和 `mana` 。 - -在一个实验室里,有 `n` 个巫师,他们必须按顺序酿造 `m` 个药水。每个药水的法力值为 `mana[j]`,并且每个药水 **必须** 依次通过 **所有** 巫师处理,才能完成酿造。第 `i` 个巫师在第 `j` 个药水上处理需要的时间为 *timeij* = `skill[i] * mana[j]`。 - -由于酿造过程非常精细,药水在当前巫师完成工作后 **必须** 立即传递给下一个巫师并开始处理。这意味着时间必须保持 **同步**,确保每个巫师在药水到达时 **马上** 开始工作。 - -返回酿造所有药水所需的 **最短** 总时间。 - -### [示例 1] - -**输入**: `skill = [1,5,2,4], mana = [5,1,4,2]` - -**输出**: `110` - -**解释**: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
药水编号开始时间巫师 0 完成时间巫师 1 完成时间巫师 2 完成时间巫师 3 完成时间
005304060
15253586064
254587886102
3868898102110
- -

举个例子,为什么巫师 0 不能在时间 t = 52 前开始处理第 1 个药水,假设巫师们在时间 t = 50 开始准备第 1 个药水。时间 t = 58 时,巫师 2 已经完成了第 1 个药水的处理,但巫师 3 直到时间 t = 60 仍在处理第 0 个药水,无法马上开始处理第 1个药水。

- - -### [示例 2] - -**输入**: `skill = [1,1,1], mana = [1,1,1]` - -**输出**: `5` - -**解释**: - -
    -
  1. 第 0 个药水的准备从时间 t = 0 开始,并在时间 t = 3 完成。
  2. -
  3. 第 1 个药水的准备从时间 t = 1 开始,并在时间 t = 4 完成。
  4. -
  5. 第 2 个药水的准备从时间 t = 2 开始,并在时间 t = 5 完成。
  6. -
- - -### [示例 3] - -**输入**: `skill = [1,2,3,4], mana = [1,2]` - -**输出**: `21` - -### [约束] - -- `n == skill.length` -- `m == mana.length` -- `1 <= n, m <= 5000` -- `1 <= mana[i], skill[i] <= 5000` - -### [Hints] - -
- 提示 1 - Maintain each wizard's earliest free time (for the last potion) as `f[i]`. - - -
- -
- 提示 2 - Let `x` be the current mana value. Starting from `now = f[0]`, update `now = max(now + skill[i - 1] * x, f[i])` for `i in [1..n]`. Then, the final `f[n - 1] = now + skill[n - 1] * x` for this potion. - - -
- -
- 提示 3 - Update all other `f` values by `f[i] = f[i + 1] - skill[i + 1] * x` for `i in [0..n - 2]` (in reverse order). - - -
- -## 思路 - -- 解决本题的第一步是确定用什么算法。因为每一瓶药水的制造都依赖上一瓶药水在某些巫师手中的完成情况,药水本身也需要一瓶一瓶地制造,所以应该使用什么算法呢? -
点击查看答案

动态规划。

- -## “动态规划”的模式 - -“动态规划”,需要用`dp`数组来保存结果。`dp[i][j]`的值可以由它的前一个(或多个)值通过公式转化出来。因此,`dp[i][j]`值是一步一步推导出来的,它和先前的`dp`记录值都有联系。 - -#### “动态规划”分为五步 - -1. 确定数组`dp`的每个值代表的**含义**。 -2. 初始化数组`dp`的值。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 -4. 根据`dp`网格数据,推导出**递推公式**。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - -#### 细说这五步 - -1. 确定数组`dp`的每个值代表的**含义**。 - - 先确定`dp`是一维数组还是二维数组。“一维滚动数组”意味着每次迭代时都会覆盖数组的值。大多时候,用“一维滚动数组”代替“二维数组”可以简化代码;但有些题目,比如要操作“两个位置可互换的数组”,为了理解方便,还是使用“二维数组”。 - - 尝试使用问题所求的`返回值`的含义作为 `dp[i]`(一维)或`dp[i][j]`(二维)的含义,约60%的概率能行。如果不行,再尝试其他含义。 - - 设计上尽量考虑保存更丰富的信息,重复信息只在某个`dp[i]`中保存一次就够了。 - - 使用简化的含义。如果用`布尔值`可以解决问题,就不要用`数值`。 -2. 初始化数组`dp`的值。`dp`的值涉及两个层面: - 1. `dp`的长度。通常是:`条件数组长度加1`或`条件数组长度`。 - 2. `dp[i]`或`dp[i][j]`的值。`dp[0]`或`dp[0][0]`有时需要特殊处理。 -3. 根据一个示例,**按顺序**填入`dp`网格数据。 - - “递推公式”是“动态规划”算法的核心。但“递推公式”是隐晦的,想得到它,就需要制表,用数据启发自己。 - - 如果原示例不够好,需要自己重新设计一个。 - - 根据示例,填入`dp`网格数据,需要“按顺序”填,这是很重要的,因为它决定了代码的遍历顺序。 - - 大多时候,从左到右,从上到下。但有时需要从右向左、由下而上、从中间向右(或左),如“回文串”问题。有时,还需要一行遍历两次,先正向,再反向。 - - 当顺序决定对了,起点就决定好了,从起点出发,“按顺序”填写`dp`网格数据,这也是在模拟程序处理的过程。 - - 在此过程中,您将获得写出“递推公式”的灵感。如果您已经能推导出公式,不需要填完网格。 -4. 根据`dp`网格数据,推导出**递推公式**。 - - 有三个特别的位置需要注意: `dp[i - 1][j - 1]`、`dp[i - 1][j]`和`dp[i][j - 1]`,当前的 `dp[i][j]`往往取决于它们。 - - 操作“两个位置可互换的数组”时,因为对称性,我们可能需要同时使用`dp[i - 1][j]`和`dp[i][j - 1]`。 -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 重点分析那些不合预期的数值。 - -读完了上面的内容,是不是感觉“动态规划”也没有那么难了?试着解出这道题吧。🤗 - -## 步骤 - -1. 确定数组`dp`的每个值代表的含义。请思考下。 - mark-detail“行”代表“药水”,“列”代表“巫师”,这在题目中已经给出暗示了。
`dp[i][j]`含义是:第`j`个巫师完成第`i`瓶药水的时间。我故意没有加“最短”这个词,因为药水在制造过程中,离不了巫师的手!mark-detail -2. `dp`数组值如何初始化? - mark-detail把值全部设置为`0`就可以了。mark-detail -3. 根据一个示例,“按顺序”填入`dp`网格数据。如何填入数据? - mark-detail“示例1”给出的那个表格的数据完全符合我们的需求,直接用它。mark-detail -4. 根据`dp`网格数据,推导出“递推公式”。“递推公式”是什么? - mark-detail条件一:第`j - 1`个巫师完成他的第`i`瓶药水工作后,第`j`个巫师才可以开始他的第`i`瓶药水的工作。
条件二:第`j`个巫师完成他的第`i - 1`瓶药水的工作后,才可以开始他的第`i`瓶药水工作。
条件三:在第`j`个巫师完成他的第`i`瓶药水工作后,第`j + 1`个巫师必须立刻开始他的第`i`瓶药水工作,即药水不等人,第`j`个巫师**不能过早开始工作**。mark-detail -5. 写出程序,并打印`dp`数组,不合预期就调整。 - - 结果你发现某些数值比预期值小了。这时,就要根据那些“异常”的数值,思考是否存在逻辑漏洞了。漏洞在哪? - mark-detail 逻辑漏洞就是:一些巫师依然过早地开始工作,导致药水在等人。mark-detail - - 如何修复逻辑漏洞? - mark-detail**从后往前**再处理一遍,因为最后一个巫师此时已经不存在过早开始工作的问题。由此可见遍历顺序的重要性。可能是从前向后,也可能是从后向前,还可能是都有。mark-detail - -## 复杂度 - -- 时间复杂度: `O(M * N)`. -- 空间复杂度: `O(N)`. - -## Ruby - -```ruby -# It may fail, but its not the problem of algorithm because same code can be accepted in other languages -# @param {Integer[]} skill -# @param {Integer[]} mana -# @return {Integer} -def min_time(skill, mana) - n = skill.size - m = mana.size - dp = Array.new(n, 0) - - m.times do |i| - n.times do |j| - dp[j] = [dp[j], dp[j - 1]].max if j >= 1 # condition 1 and 2 - time_consuming = mana[i] * skill[j] - dp[j] = [dp[j], dp[j + 1] - time_consuming].max if j < n - 1 # condition 3 - dp[j] += time_consuming - end - - # Process again from back to front to prevent any wizard from starting work too early. - (1...n).to_a.reverse.each do |j| - dp[j - 1] = dp[j] - mana[i] * skill[j] - end - end - - dp[-1] -end -``` - -## Python - -```python -# It may fail, but its not the problem of algorithm because same code can be accepted in other languages -class Solution: - def minTime(self, skill: List[int], mana: List[int]) -> int: - n = len(skill) - m = len(mana) - dp = [0] * n - - for i in range(m): - for j in range(n): - # condition 1 and 2 - if j >= 1: - dp[j] = max(dp[j], dp[j - 1]) - - time_consuming = mana[i] * skill[j] - - # condition 3 - if j < n - 1: - dp[j] = max(dp[j], dp[j + 1] - time_consuming) - dp[j] += time_consuming - - # Process again from back to front to prevent any wizard from starting work too early. - for j in range(n - 1, 0, -1): - dp[j - 1] = dp[j] - mana[i] * skill[j] - - return dp[-1] -``` - -## JavaScript - -```javascript -/** - * @param {number[]} skill - * @param {number[]} mana - * @return {number} - */ -var minTime = function (skill, mana) { - const n = skill.length; - const m = mana.length; - const dp = new Array(n).fill(0); - - for (let i = 0; i < m; i++) { - for (let j = 0; j < n; j++) { - // condition 1 and 2 - if (j >= 1) { - dp[j] = Math.max(dp[j], dp[j - 1]); - } - const timeConsuming = mana[i] * skill[j]; - // condition 3 - if (j < n - 1) { - dp[j] = Math.max(dp[j], dp[j + 1] - timeConsuming); - } - dp[j] += timeConsuming; - } - - // Process again from back to front to prevent any wizard from starting work too early. - for (let j = n - 1; j > 0; j--) { - dp[j - 1] = dp[j] - mana[i] * skill[j]; - } - } - - return dp[dp.length - 1]; -}; -``` - -## Java - -```java -class Solution { - public long minTime(int[] skill, int[] mana) { - int n = skill.length; - int m = mana.length; - long[] dp = new long[n]; - - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // condition 1 and 2 - if (j >= 1) { - dp[j] = Math.max(dp[j], dp[j - 1]); - } - long timeConsuming = (long) mana[i] * skill[j]; - // condition 3 - if (j < n - 1) { - dp[j] = Math.max(dp[j], dp[j + 1] - timeConsuming); - } - dp[j] += timeConsuming; - } - - // Process again from back to front to prevent any wizard from starting work too - // early - for (int j = n - 1; j > 0; j--) { - dp[j - 1] = dp[j] - (long) mana[i] * skill[j]; - } - } - - return dp[n - 1]; - } -} -``` - -## C# - -```csharp -public class Solution -{ - public long MinTime(int[] skill, int[] mana) - { - int n = skill.Length; - int m = mana.Length; - long[] dp = new long[n]; - - for (int i = 0; i < m; i++) - { - for (int j = 0; j < n; j++) - { - // condition 1 and 2 - if (j >= 1) - { - dp[j] = Math.Max(dp[j], dp[j - 1]); - } - long timeConsuming = (long)mana[i] * skill[j]; - // condition 3 - if (j < n - 1) - { - dp[j] = Math.Max(dp[j], dp[j + 1] - timeConsuming); - } - dp[j] += timeConsuming; - } - - // Process again from back to front to prevent any wizard from starting work too early - for (int j = n - 1; j > 0; j--) - { - dp[j - 1] = dp[j] - (long)mana[i] * skill[j]; - } - } - - return dp[n - 1]; - } -} -``` - -## C++ - -```cpp -class Solution { -public: - long long minTime(vector& skill, vector& mana) { - int n = skill.size(); - int m = mana.size(); - vector dp(n, 0); - - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // condition 1 and 2 - if (j >= 1) { - dp[j] = max(dp[j], dp[j - 1]); - } - long long time_consuming = (long long)mana[i] * skill[j]; - // condition 3 - if (j < n - 1) { - dp[j] = max(dp[j], dp[j + 1] - time_consuming); - } - dp[j] += time_consuming; - } - - // Process again from back to front to prevent any wizard from - // starting work too early - for (int j = n - 1; j > 0; j--) { - dp[j - 1] = dp[j] - (long long)mana[i] * skill[j]; - } - } - - return dp[n - 1]; - } -}; -``` - -## Go - -```go -func minTime(skill []int, mana []int) int64 { - n := len(skill) - m := len(mana) - dp := make([]int64, n) - - for i := 0; i < m; i++ { - for j := 0; j < n; j++ { - // condition 1 and 2 - if j >= 1 && dp[j-1] > dp[j] { - dp[j] = dp[j-1] - } - timeConsuming := int64(mana[i]) * int64(skill[j]) - // condition 3 - if j < n-1 { - if dp[j+1]-timeConsuming > dp[j] { - dp[j] = dp[j+1] - timeConsuming - } - } - dp[j] += timeConsuming - } - - // Process again from back to front to prevent any wizard from starting work too early - for j := n - 1; j > 0; j-- { - dp[j-1] = dp[j] - int64(mana[i])*int64(skill[j]) - } - } - - return dp[n-1] -} -``` - -## Other languages - -```java -// Welcome to create a PR to complete the code of this language, thanks! -``` - -亲爱的力扣人,为了您更好的刷题体验,请访问 [LeetCode.blog](https://leetcode.blog/zh)。 -本站敢称力扣题解最佳实践,终将省你大量刷题时间! - -原文链接:[3494. 酿造药水需要的最少总时间 - LeetCode Python/Java/C++/JS/C#/Go/Ruby 题解](https://leetcode.blog/zh/leetcode/3494-find-the-minimum-amount-of-time-to-brew-potions). - -GitHub 仓库: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java). - diff --git a/zh/README.md b/zh/README.md deleted file mode 100644 index c7452d9..0000000 --- a/zh/README.md +++ /dev/null @@ -1 +0,0 @@ -# 力扣中文题解